ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [스칼라] 컬렉션
    스칼라 2022. 2. 23. 00:11

    Programming in Scala 4th edition 17장

     

    1. 시퀀스

    시퀀스 타입: 순서가 정해진 데이터 그룹을 가지고 작업할 수 있다. 시퀀스 타입들은 인덱스로 원소를 조회할 수 있다.

     

    리스트

    List: 변경 불가능한 연결리스트로 구현되어있다. head 추가, 삭제를 빠르게 처리 할 수 있다.

     

    배열

    Array: 배열은 임의의 위치에 있는 원소를 효율적으로 접근하게 한다.

    val integerArray = new Array[Int](5)
    integerArray // Array(0, 0, 0, 0, 0)
    
    val integerArray2 = Array(1, 2, 3, 4, 5)
    integerArray2 // Array(1, 2, 3, 4, 5)

     

    리스트 버퍼

    List는 맨 앞에 추가/제거를 할 때는 적절하지만 끝쪽에 연산을 할 경우 성능이 떨어진다. 만약 끝에 원소를 추가해가며 리스트를 만들 경우에는 거꾸로 리스트를 만들어서 reverse를 이용하거나 ListBuffer를 사용할 수 있다.

    ListBuffer: 변경 가능한 객체로 append, prepend를 이용해 원소를 추가한뒤 toList를 사용

     

    val list = new ListBuffer[Int]
    list.append(1)
    list.append(2)
    list.append(3)
    list.prepend(0)
    list.prepend(-1)
    list.toList
    
    val list1 = new ListBuffer[Int]
    list1 += 1
    list1 += 2
    list1 += 3
    0 +=: list1
    -1 +=: list1
    list1.toList

    ListBuffer 에서 += 과 +=: 은 각각 append, prepend이다.

     

    배열 버퍼

    ArrayBuffer: 끝과 시작 부분에 원소를 추가하거나 삭제할 수 있다. 추가/삭제는 선형 시간이 걸리지만 새롭게 배열을 할당해야 할 때가 있어서 선형 시간이 걸리기도 한다.

    import scala.collection.mutable.ArrayBuffer
    
    val arrayBuffer = new ArrayBuffer[Int]
    arrayBuffer += 1
    arrayBuffer += 2
    arrayBuffer

    배열에서 사용하는 모든 메서드를 사용할 수 있다.

     

    문자열(StringOps를 통해서)

    StringOps에는 문자열을 이용한 시퀀스 메서드들이 구현되어있다.

    "abc".exists(_ == 'a')

    exists 메서드는 String 클래스 자체에는 존재하지 않고 StringOps에 존재한다. 스칼라 컴파일러는 String을 StringOps로 알아서 변환해준다.

     

    2. 집합과 맵

    스칼라는 Set과 Map에 대해서 mutable한 것과 immutable한 것 둘 다 제공한다. 기본적으로 그냥 Set이나 Map을 사용하려 하면 immutable한 객체를 뜻하고 scala.collection.mutable을 이용하여 Set, Map을 사용해야 mutable객체를 사용할 수 있다.

     

    집합

    Set: 객체가 최대 하나만 들어가도록 보장 (동일성은 ==으로 판단한다)

    val words = Array("Korea", "USA", "KOREA", "usa", "korea")
    val set = scala.collection.mutable.Set[String]()
    
    for(word <- words) {
      set += word.toLowerCase()
    }
    
    set // Set("korea", "usa")

    위는 배열안에서 대소문자를 구분하지 않고 나라이름만 Set에 담는 예제이다. 아래는 immutable Set의 다양한 연산이다.

    val immutableSet = Set(1, 2, 3, 4)
    immutableSet + 5 // Set(5, 1, 2, 3, 4) 원소를 추가하여 새 집합을 반환. 집합은 순서를 보장하는것과는 관련이 없다.
    immutableSet - 4 // Set(1, 2, 3)  원소를 제외하여 새 집합을 반환
    immutableSet ++ List(3, 4, 5, 6) // Set(1, 2, 3, 4, 5, 6) 원소 다수를 추가하여 새 집합 반환
    immutableSet -- List(0, 1, 2)    // Set(3, 4)  원소 다수를 제외하여 새 집합을 반환
    immutableSet & Set(2, 3)         // Set(2, 3)  교집합 반환

    아래는 mutable Set의 다양한 연산이다.

    val mutableSet = scala.collection.mutable.Set.empty[Int]
    mutableSet += 1 // Set(1)
    mutableSet ++= List(2, 3, 4) // Set(1, 2, 3, 4)
    mutableSet -= 1 // Set(2, 3, 4)
    mutableSet --= List(2, 3) // Set(4)

     

    맵은 키와 값으로 이루어진 구조이다. 주로 어떤 키에 값을 저장하고 그 키를 가지고 맵에 조회를 하여 값을 얻는 형태로 활용한다. 키, 값의 타입을 모두 지정하는 형태로 생성할 수 있다.

    val mutableMap = scala.collection.mutable.Map[String, Int]()
    
    mutableMap("Apple") = 1
    mutableMap("Banana") = 2
    
    mutableMap // Map(Banana -> 2, Apple -> 1)
    
    mutableMap("Apple") // 조회, 1 리턴
    mutableMap("apple") // 없는 키이므로 예외 발생

    immutable Map의 주요 연산자이다.

    val nums = Map("a" -> 1, "b" -> 2)
    nums + ("c" -> 3)                 // Map(a -> 1, b -> 2, c -> 3)
    nums - "a"                        // Map(b -> 2)
    nums ++ List("c" -> 3, "d" -> 4)  //  Map(a -> 1, b -> 2, c -> 3, d -> 4)
    nums -- List("a" -> 1, "b" -> 2)  //  Map()

     

    Set1, Set2, Set3, Set4, HashSet, Map1, Map2, Map3, Map4, HashMap

    스칼라에서 Set() 이나 Map() 팩토리 메서드를 이용하여 Set, Map을 만들 경우 초기화 원소 숫자에 따라서 어떤 구현 클래스가 사용될지가 달라진다. 원소 4개 까지는 각 갯수에 최적화된 Set, Map이 사용되고 5이상부터는 HashSet, HashMap이 이용된다.

     

    SortedSet, SortedMap

    Set, Map은 기본적으로 순서를 보장하지 않는다. 만약 순서를 보장하는 Set, Map이 필요하면 SortedSet, SortedMap 트레이트를 사용해야한다. SortedSet, SortedMap은 TreeSet, TreeMap클래스로 구현되어 있고 레드블랙 트리를 이용한다. SortedSet을 이용할 때는 Set을 이루는 원소타입이 Ordering 트레이트를 정의해야하고 SortedMap을 이용할 때는 키 타입이 Ordering 트레이트를 정의해야한다.

    import scala.collection.immutable.{TreeSet, TreeMap}
    
    val treeSet = TreeSet(3, 2, 4, -1, -3)
    treeSet // TreeSet(-3, -1, 2, 3, 4)
    
    val treeMap = TreeMap(
      "d" -> 4,
      "b" -> 100,
      "a" -> 1
    )
    
    treeMap // Map(a -> 1, b -> 100, d -> 4)

     

    3. 변경 가능 컬렉션(mutable)과 변경 불가능 컬렉션(immutable)

    변경 불가능 컬렉션은 공간을 덜 차지하고 가독성을 높여주는 측면에서 장점이 있다. 변경 불가능 컬렉션으로 처리가 되는 경우면 변경 불가능 컬렉션을 우선 사용하는것이 대부분의 경우에서 좋다. 변경 불가능 컬렉션은 기본적으로 += 연산자를 지원하지 않지만 스칼라 컴파일러는 var로 선언된 변경 불가능 컬렉션의 경우 += 를 사용할 수 있도록 도와준다. 

    var varImmutableSet = Set(1, 2)
    varImmutableSet += 3 // Set(1, 2, 3)
    
    val valImmutableSet = Set(1, 2)
    valImmutableSet += 3 // 허용되지 않음

     

    4. 컬렉션 초기화

    가장 일반적인 방법은 컬렉션 클래스의 동반 객체의 apply를 이용하여 초기화를 하는 것이다. 이 경우 스칼라 컴파일러가 타입추론을 하기때문에 타입을 꼭 명시하지 않아도 된다.

    어떤 컬렉션을 이용해 다른 컬렉션을 만들고 싶으면 to를 이용한다.

    val colors = List[String]("blue", "yellow", "red", "green")
    import scala.collection.immutable.TreeSet
    colors to TreeSet

     

    배열이나 리스트로 바꾸기

    배열이나 리스트로 변경하려면 toList, toArray를 활용하면 된다.

    val treeSet = TreeSet(8, -1, 4, -10)
    treeSet.toList     // List(-10, -1, 4, 8)
    treeSet.toArray    // Array(-10, -1, 4, 8)

    toArray, toList로 변환한 배열이나 리스트의 원소 순서는 그 전의 컬렉션의 이터레이터가 반환하는 순서와 동일하다. TreeSet은 순서를 보장하기 때문에 TreeSet으로부터 만든 List와 Array도 순서가 유지되어있다.

     

    5. 튜플

    튜플은 정해진 갯수의 원소를 묶어 만든다. 여러 타입이 섞일 수 있다. (그래서 Iterator를 만들지 못한다.)

    val tuple = ("a", 1)
    tuple
    
    tuple._1
    tuple._2
    
    val (a, one) = tuple
    print(a, one)

     

    '스칼라' 카테고리의 다른 글

    [스칼라] 추상 멤버  (0) 2022.02.25
    [스칼라] getter setter  (0) 2022.02.23
    [스칼라] 리스트  (0) 2022.02.22
    [스칼라] 케이스 클래스와 패턴 매치  (0) 2022.02.21
    [스칼라] 트레이트  (0) 2022.02.20

    댓글

Designed by Tistory.