스칼라100(5) List-map, foreach

2,226 views
Skip to first unread message

최정열

unread,
Jan 7, 2014, 11:30:03 AM1/7/14
to scala...@googlegroups.com

List -mapforeach

이번에는 리스트의 메소드들에 대해서 알아보도록 하겠습니다. 메소드의 종류가 좀 많습니다만, 어휘가 많으면 간결한 표현도 가능하고, 더불어 의도 또한 전달하기 좋아지겠죠.

map

가장 자주 사용하는 대표적인 메소드는 map이라고 볼 수 있겠네요. 컬렉션의 요소를 말 그대로 매핑 합니다.

val ls = List(1, 2, 3)

위와 같은 배열이 있을 때, 각각의 요소에 x2를 하고 싶을 때 map을 사용 할 수 있습니다.

val ls2 = ls.map((x: Int) => x * 2)
  • (x: Int)에서, : 우측에는 인자(x)의 타입을 기입합니다. 타입 표기는 생략가능한 경우도 있고, 반드시 필요한 경우도 있습니다. 이 경우는 컴파일러가 추론 가능하니 생략하는 편이 좋겠네요. (생각보다 스칼라 컴파일러가 똑똑합니다. 아쉬울때도 있지만…)

리스트에 Int 타입이 담긴 것이 뻔하니, 다음처럼 생략이 가능합니다.

val ls2 = ls.map(x => x * 2)    //> ls2 = List(2, 4, 6)

조금 더 줄일 수 있습니다.

val ls2 = ls.map( _ * 2 )    //> ls2 = List(2, 4, 6)
  • _는 place holder라고 불립니다. 뭐가 올지 뻔한 상황에서 사용됩니다. 개인적으로 전라도 사투리의 “거시기”와 비슷하다고 생각합니다. (“거시기 두 배로 만들라…”(죄송합니다.;))
  • 다시 한번 말씀드리지만, 새로운 객체가 생성되어 ls2에 할당 되는 것입니다. ls에 저장 된 객체의 값(1, 2, 3)이 변경되는 것이 아닙니다.
    ls     //> List(1, 2, 3)
    ls2    //> List(2, 4, 6)
    

그리고 => 기호가 보입니다.

map(x => x * 2)

=> 기호는 정식 명칭은 right arrow라고 했다고 합니다. (오더스키 아저씨가…) 그런데, 아시다시피 ->기호(map에서 key-value를 지정 할 때 사용)도 있어서 혼란의 여지가 있습니다. 그래서 rocketfat arrow 라는 이름도 거론 되는 것 같습니다. 참고: what-is-called-in-scala

아무튼, => 왼쪽에 있는 x인자는 리스트의 요소입니다.(이름은 변수명 짓듯이 임의로 정할 수 있습니다.), 즉x는 순차적으로 123 각각에 대응합니다. 그리고, => 우측에는 원하는 표현식을 써주면 됩니다.

  • 여기서, x => x * 2부분을 function literal 이라고 부릅니다.

이름에서도 알 수 있듯이 x => x * 2는 함수(리터럴)입니다.

위의 코드에서 함수(리터럴)를 추출해서, 다음과 같이 바꿔 보겠습니다.

val double = (x: Int) => x * 2

val ls2 = ls.map(double)    // ls2 = List(2, 4, 6)

(x:Int) => x * 2 부분이 거의 비슷하죠. val로 할당한 함수는 다른 곳에서 재사용 할 수 있겠네요.

def키워드를 이용해서, 메소드를 정의 해서 사용 할 수도 있습니다.

def double(x: Int) = x * 2
ls.map(double)    // ls = List(2, 4, 6)
  • 정확히 말하면 여기서 def로 선언 된 부분은 함수(function)이라고 부르지 않고 메소드라고 하는 편이 옳습니다. 지금으로써는 크게 중요하지 않지만, 스칼라에서 말하는 함수와 메소드를 구분하는 것은 필요합니다. 메소드는 객체내에서 필드 조작에 주 목적이 있고, 함수는 그 자체가 독립적으로 사용되는 성격이 강합니다. (나중에 자세히 다룰 예정입니다.)

다시 map으로 돌아와서 Int요소를 String 으로 변경하는 코드를 보겠습니다.

val ls = List(1, 2, 3)
ls.map(x => x.toString)    // List("1", "2", "3")

다음은 대문자로 변경하는 코드입니다.

val cities = List("seoul", "tokyo", "paris") 
cities.map(city => city.toUpperCase())    //> List("SEOUL", "TOKYO", "PARIS")

각각 _를 사용해서, 다음과 같이 줄일 수 있습니다.

ls.map( _.toString )
cities.map(_.toUpperCase())

map블럭을 ( ) 대신 { }로 감싸고 ;로 구분해서 다른 일들을 할 수도 있습니다.

cities.map{city => println(city); city.toCharArray()}

{ }를 사용하면 여러줄에 기술할 수도 있고, ;도 생략 할 수 있습니다.

cities.map {
  city =>
    println(city)
    city.toCharArray()
}
//> seoul
//> tokyo
//> paris
//> List(Array(s, e, o, u, l), Array(t, o, k, y, o), Array(p, a, r, i, s))

foreach

그리고foreach메소드가 있습니다. 단순히()내의 문장을 수행합니다.

val ls = List(1, 2, 3)
ls.foreach(x => println(x))

물론 할당도 가능하지만, 이경우는Unit = ()(아무것도 없음. void와 비슷함)이 됩니다.

val res = ls.foreach(x => println(x))    // res  : Unit = ()

그래서 foreach 문에서 사이드이펙트를 일으키는 작업이나, 리스트 외부의 변수에 접근하는 작업이 수행되곤 합니다. 마찬가지로 _를 사용해서, 코드를 줄여보겠습니다.

ls.foreach(println(_)) 
//> 1
//> 2
//> 3

심지어는, _도 생략 할 수 있습니다. (foreach에서 전달되는 인자(arg)도 뻔하고, println에서 받는 인자(param)도 뻔하니… 인자를 배달하는 일은 컴파일러가 알아서 해주는 것이죠.)

ls.foreach(println)

좀 깔끔하게 다음과 같이 바꿀수도…

ls foreach println

다음 코드는 foreach 외부에 변수를 두어서 합계를 구하는 코드입니다.

var sum = 0
ls.foreach(x => sum += x)
println(sum)    // sum = 6

foreach문이 길어지는 경우에도 다음처럼 ( )를 { }로 바꿀 수 있습니다. (항상 ( )를 { }로 대체 할 수 있는 것은 아닙니다.)

ls.foreach {
  x =>
    val y = doSomething(x)
    println(y)
    sum += y
}

Scala100 Home


윤정부

unread,
Jan 7, 2014, 6:58:34 PM1/7/14
to scala...@googlegroups.com
책을 쓰셔두 되겠네요.. 살짝 기대해 볼까요?ㅋㅋㅋ


2014년 1월 8일 오전 1:30, 최정열 <mye...@gmail.com>님의 말:

--
Google 그룹스 '라 스칼라 코딩단' 그룹에 가입했으므로 본 메일이 전송되었습니다.
이 그룹에서 탈퇴하고 더 이상 이메일을 받지 않으려면 scala-korea...@googlegroups.com에 이메일을 보내세요.
이 그룹에 게시하려면 scala...@googlegroups.com(으)로 이메일을 보내세요.
웹에서 이 토론을 보려면 https://groups.google.com/d/msgid/scala-korea/cfb6ada3-caa7-47a5-ba46-32fc6361a4af%40googlegroups.com 을(를) 방문하세요.
더 많은 옵션을 보려면 https://groups.google.com/groups/opt_out을(를) 방문하세요.

Reply all
Reply to author
Forward
0 new messages