본문 바로가기

안드로이드/Kotlin

[Kotlin] 스트림 함수(확장 함수) - map, filter

개요

자바 8에서는 리스트나 맵과 같은 컬렉션의 자료들을 손쉽게 다룰 수 있는 스트림(stream) 기능을 제공한다. 스트림은 컬렉션의 자료를 다른 타입으로 변경하거나, 새로운 자료를 추가로 생성하는 등의 작업을 쉽게 도와준다.

 

코틀린에서는 이와 유사한 기능을 확장 함수의 형태로 제공한다. 확장 함수는 내부적으로 자바의 스트림을 사용하지 않아 엄밀히 말하면 스트림 함수가 아니긴하다.

 

 

변환-map()

map() 함수는 컬렉션 내 요소를 다른 값이나 타입으로 변경할 때 사용한다.

val cities = listOf("Seoul", "Tokyo", "New york")

//도시 이름을 대문자로 변환하여 저장 후 출력
cities.map{city -> city.toUpperCase()}.
	  .forEach{ println(it) }

//도시 이름을 길이로 변화하여 저장 후 출력
cities.map{city -> city.length }.
	  .forEach{ println("LENGTH=$it") }
      

--결과--
SEOUL
TOKYO
NEW YORK
LENGTH=5
LENGTH=5
LENGTH=9

 

mapNotnull()은 컬렉션 내 각 요소를 변환함과 동시에 요소가 null인 경우 무시한다.

val cities = listOf("Seoul", "Tokyo", "New york")

//도시 이름 길이가 5 이상이 아닌 경우 null로 변환
cities.mapNotNull{city -> if(city.length>5) city else null }.
	  .forEach{ println(it) }
      

--결과--
SEOUL
TOKYO

 

groupBy()는 컬렉션 내 요소들을 지정한 기준에 다라 분류하여, 각 요소들의 리스트를 포함하는 Map의 형태로 반환한다.

val cities = listOf("Seoul", "Tokyo", "New york")

//도시 이름이 5 이상이면 "A" 그룹, 그렇지 않으면 "B" 그룹에 대입
cities.groupBy{city -> if(city.length>5) "A" else "B" }.
	  .forEach{key,cities ->  println("key=$key, cities=$cities") }
      

--결과--
key=A, cities=[Seoul, Tokyo]
key=B, cities=[New york]

 

필터-filter(), take(), drop(), first(), last(), distinct()

filter() 함수는 컬렉션 내 인자들 중 주어진 조건과 일치하는 인자들만 필터링한다.

val cities = listOf("Seoul", "Tokyo", "New york")

//도시 이름이 5 이상인 요소만 통과
cities.filter{city -> city <= 5 }.
	  .forEach{println(it)}
      

--결과--
Seoul
Tokyo

 

take() 함수는 컬렉션 내 요소들 중 인자로 받은 수 만큼의 리스트를 반환한다.

이와 유사한 함수로 takeLast(), takeWhile(), takeLastWhile() 등이 존재한다. takeLast는 뒤에서 부터 리스트를 반환하고, takeWhile은 앞에서 부터 조건이 만족할 때까지만 반환한다. 

위에서 중요한 점은 컬렉션의 순서는 유지된다는 점이다.

val cities = listOf("Seoul", "Tokyo", "Mountain View", "New york". "Singapore")

cities.take(1).forEach{print(it)} 
//Seoul

cities.takeLast(2).forEach{print(in)} 
//****순서 유의****
//New york
//Singapore

cities.takeWhile{city -> city.lenght <=5 }
		.forEach{print(in)}
//Seoul
//Tokyo


cities.takeLstWhile{city -> city.lenght < 13 }
		.forEach{print(in)}
//****순서 유의****
//New yotk
//Singapore

 

drop() 함수는 take() 함수와 반대 역할을 하며, 조건을 만족하는 항목을 컬렉션에서 제외 시킨 결과를 출력한다. take()와 유사게 last, while이 존재한다.

마찬가지로 중요한 점은 컬렉션의 순서는 유지된다는 점이다.

val cities = listOf("Seoul", "Tokyo", "Mountain View", "New york". "Singapore")

cities.drop(1).forEach{print(it)} 
//Tokyo
//Mountain View
//New york
//Singapore

cities.dropLast(2).forEach{print(in)} 
//****순서 유의****
//Seoul
//Tokyo
//Mountain View

cities.dropWhile{city -> city.length <=5 }
		.forEach{print(in)}
//Mountain View
//New york
//Singapore


cities.droLastWhile{city -> city.length < 13 }
		.forEach{print(in)}
//****순서 유의****
//Seoul
//Tokyo
//Mountain View

 

first()last() 함수는 각각 컬렉션 내의 첫번째 요소와 마지막 요소 단 하나만을 반환하는 역할을 한다. 추가로, 조건을 만족하는 첫번째 요소, 마지막 요소를 반환하는 것도 가능하다. firstOrNull(), lastOrNull() 등을 통해 만족하는 값이 없으면 null을 반환하는 것도 가능하다.

val cities = listOf("Seoul", "Tokyo", "Mountain View", "New york". "Singapore")

println(cities.first())
//Seoul

println(cities.last())
//Singapore

println(cities.first{city -> city.length > 5})
//Mountain View

println(cities.last{city -> city.length > 5})
//Singapore

println(cities.firstOrNull{city -> city.isEmpty()})
//null

println(cities.lastOrNull{city -> city.isEmpty()})
//null

 

distinct() 함수는 컬렉션 내의 모든 중복을 제거한 결과를 반환한다. 중복 여부는 equals()를 통해 확인한다.

distinctBy()를 통해 비교에 사용할 키 값을 직접 설정하는 것도 가능하다.

val cities = listOf("Seoul", "Tokyo", "Mountain View", "Seoul". "Tokyo")

cities.distinct().forEach{println(it)}
//Seoul
//Tokyo
//Mountain View

cities.distinctBy{city -> city.length}
      .forEach{println(it)}
//Seoul
//Mountain View