Outsider's Dev Story

Stay Hungry. Stay Foolish. Don't Be Satisfied.
RetroTech 팟캐스트 44BITS 팟캐스트

Scala의 Collection

스칼라는 컬렉션으로 List, Set, Map가 있으며  List는 순서가 있는 컬렉션이고 Set은 순서가 없는 컬렉션 Map은 Key-Value쌍으로 된 Dictionary입니다. mutable버전의 컬렉션이 제공되기는 하지만 항상 그렇듯이  Thread Safe한데다가 사이드이펙트가 없는 Immutable 컬렉션을 더 권장하고 있습니다. 컬렉션은 scala.collection.mutable과 scala.collection.immutable의 패키지에서 선택하여 사용할 수 있습니다.


val sites = Set("google.com", "yahoo.com")
var newSites = sites
newSites += "daum.net"

println("sites : " + sites)
println("newSites : " + newSites)
// output
// sites : Set(google.com, yahoo.com)
// newSites : Set(google.com, yahoo.com, daum.net)

위의 코드처럼 "daum.net"을 추가하면 기존의 Set을 수정하지 않고 새 엘리먼트가 추가된 새로운 Set을 리턴하는데 이는 기본적으로 인클루드되는 Predef가 immutable구현의 Set과 Map의 별칭을 제공하고 있기 때문에 Immutable Set을 사용하게 됩니다. new없이 Set의 인스턴스를 생성했는데 Set(1,2,3)을 사용하면 Set[Int]를 리턴받게 되는데 이는 factory메서드라고도 불리는 apply()때문에 가능합니다.



Set
val temp = Set("First", "Second", "Third")

filter() -
원하는 문자열이 들어간 결과를 검색합니다. - temp filter(_ contains "First") 하면 Fisrt가 추가된 새로운 Set이 리턴됩니다.

mkString() - 각 엘리먼트들을 파라미터로 넘김값으로 연결한 스트링을 생성합니다
: temp.mkString(", ")

++() - 2개의 Set을 합쳐서 새로운 Set을 생성합니다
: temp ++ Set("111", "222")

**() - 2개의 Set에서 공통적인(intersect) 부분을 찾아줍니다
: temp ** Set("Second", "333")

foreach() - Set 엘리먼트를 이터레이트합니다
: temp.foreach { a => println( a ) }




Map

val temp = Map("a" -> "ex1", "b" -> "ex2", "c" -> "ex3")

filterKeys() - 특정키로 선택한 Map을 리턴합니다. : temp filterKeys(_ startsWith "a" )

filter() - 키대신 값을 통해서 필터링 할 수 있으며 filter()에 제공한 펑션밸류는 (key, value) 튜플을 받습니다.
temp filter { a =>
    val (key, value) = a
    (key startsWith "a") && (value contains "ex")
}

get() - 특정 엘리먼트를 얻을 수 있습니다. 주어진 키를 위한 값이 없다면 리턴타임은 Option[T]이고 결과는 Some[T]이거나 None이 됩니다.(여기서 T는 Map 값의 타입입니다.) : temp.get("a")
get()하는 대신에 apply()를 사용해서도 키에 대한 값을 얻을수 있는데 차이점은 Option[T] 대신에 값을 리턴하게 되며 주어진 키에 맞는 값이 없다면 예외를 던지기 때문에 코드를 try-catch블럭안에 넣어줘야 합니다.

update를 사용하면 엘리먼트를 추가할 수 있습니다만 immutable 컬렉션이기 때문에 원래의 Map에 추가한 새로운 Map을 리턴합니다. : temp.update("d", "ex4")
할당의 좌편에서 클래스나 인스턴스에 괄호를 사용하면 자동으로 update()메서드를 호출하기 때문에 X() = b는 X.update(b)와 동일하게 사용할 수 있습니다. update()에 파라미터를 전달한다면 다음과 같이 괄호 안에 파라미터를 두면 됩니다. X(a) = b는 X.update(a,b)와 동일합니다.




List
List는 Set, Map과는 다르게 오직 Immutable만 가지고 있습니다. 첫 엘리먼트는 head 메서드를 이용해서 접근하고 나머지는 모두 tail메서드를 이용해서 접근합니다. last() 메서드는 엘리먼트를 모두 가로질러야 하기 때문에 head나 tail보다 많은 비용이 들게 됩니다.

val temp = List("ex1", "ex2", "ex3", "ex4")

head() - List의 첫번째 엘리먼트에 접근할수 있습니다. 0부터 시작하는 index를 이용해서도 접근이 가능합니다. : temp.head 와 temp(0) 은 같습니다.

::() - List앞에 엘리먼트를 추가합니다. : "ex5" :: temp

:::() - 메서드 뒤에 나오는 리스트 앞에 리스트를 추가합니다. : temp ::: List("ex6", "ex7")

filter() - 특정조건을 만족시키는 엘리먼트를 찾습니다. : temp.filter(_ contains "ex")

forall() - 모든 엘리먼트가 조건을 만족하는지 확인합니다. : temp.forall(_ contains "ex")

exists() - 조건을 만족시키는 엘리먼트가 있는지 확인합니다. : temp.exists(_ contains "ex2")




메서드명의 관례(Method Name Convention)
메서드명의 첫번째 캐릭터로 실행의 우선순위를 결정하는데 메서드의 마지막 캐릭터는 메서드 호출의 타겟을 결정하는데 영향을 줍니다. 메서드명 끝에 콜론(:)이 있다면 메서드의 호출 타겟이 메서드 뒤에오는 인스턴스가 됩니다.  그래서 value :: list는 실제로는 value를 아규먼트로 갖는 list로 list.::(value)와 같습니다.

단항연산자로


class Ex { 
    def unary_+ = println("1") 
    def unary_! = println("2") 
}
val sample = new Ex
+sample 
!sample

단항연산자로 +나 -를 사용하면 unary_+()나 unary_!()를 호출합니다.




for 표현식

for([pattern <- generator; definition*]+; filter*)
    [yield] expression

위 정의처럼 for 표현식은 정의로 0개이상의 defenition과 filter와 함께 하나 이상의 generator를 파라미터로 취하며 세미콜론(;)으로 분리가 되어 있습니다. yield 키워드는 선택적이며 Unit대신의 값의 List를 리턴합니다.

val result = for (i <- 1 to 10)
    yield i * 2

위 코드는 1부터 10까지의 수의 2배값의 컬렉션이 리턴됩니다.

val result2 = (1 to 10).map(_ * 2)

map을 사용하면 같은 결과를 위와 같은 코드로 얻을 수 있습니다.

val doubleEven= for (i <- 1 to 10; if i % 2 == 0)
    yield i * 2

위 코드처럼 filter를 사용하면 짝수일 경우에만 2배값으로 처리하도록 할 수 있습니다. 펑셔널 프로그래밍에서 이것을 List comprehension 이라고 부르며 아래와 같이 curly brace로 사용할 수도 있습니다.

for {
    i <- 1 to 10
    if i % 2 == 0
}
    yield i * 2

아래처럼 제너레이터와 함께 정의를 둘 수 있습니다.

val temp = List("ex1", "ex2", "ex3")
val result = for( t <- temp; p = t + " is good") yield p // List(ex1 is good, ex2 is good, ex3 is good)

제너레이터를 2개 사용하려면 아래처럼 사용합니다.

for (i <- 1 to 3; j <- 4 to 6) {
    print("[" + i + "," + j + "] ")
}
// output
// [1,4] [1,5] [1,6] [2,4] [2,5] [2,6] [3,4] [3,5] [3,6]

2010/08/04 03:52 2010/08/04 03:52