버튼 수집상

[Kotlin] 유용한 Collection 함수 본문

TIL - Kotlin

[Kotlin] 유용한 Collection 함수

cocokaribou 2023. 7. 4. 14:05

저번에 쓴 글에서 누락된 함수들이 있어서 추가.

 

[Kotlin] 유용한 List 고차함수

컬렉션 안에 필요한 정보를 끄집어낼 때 몇 겹씩 되는 for문을 돌리는 대신 고차함수를 쓰면 편리하다. 그렇다고 소스코드에서 for문을 안 쓰는 것은 아니나 데이터의 뎁스가 깊을 때 가독성이 좋

collectingbuttons.tistory.com

 

평소에 자주 쓰는 코틀린의 Collection 함수들 모아봤다.

람다함수와 컬렉션 확장함수가 섞여있다.

any

list.any { it -> 체크하고 싶은 조건문 }

조건에 해당하는 요소가 하나라도 있는지 true / false 리턴

val list = listOf(
    listOf("one"),
    listOf("two", "three"),
    listOf("four")
)

val result = list.any { innerList ->
    innerList.size > 2
}
print(result)
// false

filterNot

list.filterNot { it -> 필터링해서 남기고 싶지 않은 조건 }

(사실 filter 를 써서 조건문을 수정하는 쪽을 더 많이 쓰긴 한다)

class Fruit(
    val name: String,
    val state: State
)
enum class State {
    FRESH,
    ROTTEN
}

val fruits = listOf(
    Fruit("apple", State.FRESH),
    Fruit("grape", State.ROTTEN),
    Fruit("kiwi", State.ROTTEN),
    Fruit("peach", State.FRESH),
)

val freshFruits: List<String> =
    fruits
        .filterNot { fruit -> fruit.state == State.ROTTEN }
        .map { fruit -> fruit.name }

print(freshFruits)
// [apple, peach]

joinToString

list.joinToString() { it -> String으로 포맷하고 싶은 값 }

오브젝트 리스트에서 값을 확인할 때 자주 사용한다.

separator, prefix, postfix 인자를 추가할 수 있다.

예시1

val fruits = listOf(
    Fruit("apple", State.FRESH),
    Fruit("grape", State.ROTTEN),
    Fruit("kiwi", State.ROTTEN),
    Fruit("peach", State.FRESH),
)

// 디폴트 separator ", "
val fruitNameString = fruits.joinToString(separator = " ") { fruit -> fruit.name }

print(fruitNameString)
// apple grape kiwi peach

예시2

val list = List(10){ (0 until 10).random() } // Immutable 리스트 디폴트 값으로 초기화하기
val blank = "[]"
    
println("0,1,2,3,4,5,6,7,8,9")

val formattedString = 
    list.joinToString(separator = "\n") { item -> 
        blank.repeat(item) + item.toString() + blank.repeat(9 - item) // lamda 마지막 줄에 String 리턴
    }

println(formattedString)

// 0,1,2,3,4,5,6,7,8,9
// [][]2[][][][][][][]
// [][][][][]5[][][][]
// []1[][][][][][][][]
// [][][][]4[][][][][]
// [][][][][]5[][][][]
// [][][][]4[][][][][]
// 0[][][][][][][][][]
// [][][][][][]6[][][]
// [][][][][][]6[][][]
// [][][][][]5[][][][]

maxOf

list.maxOf { it -> 비교해서 리턴하고 싶은 값 }

리스트에서 최대값을 리턴한다.

최소값을 리턴하는 minOf도 있다.

class Fruit(
    val name: String,
    val price: Int
)

val fruitList = listOf(
    Fruit("orange", 3000), 
    Fruit("grapefruit", 3800),
    Fruit("berry", 3400),
    Fruit("apple", 1600),
    Fruit("melon", 8000), 
    Fruit("muscat", 5000)
)

val highestPrice : Int = fruitList.maxOf { it.price }
println(highestPrice)
// 8000

maxBy

list.maxBy { it -> 요소를 리턴하기 위해 비교하는 값 }

람다식 안에서 비교한 값이 최대값인 요소를 리턴한다.

class FruitSection (
    val color : String,
    val fruitList : List<Fruit>
)

val fruitSections : List<FruitSection> = 
    listOf(
        FruitSection(
            color = "orange",
            fruitList = listOf(
                Fruit("orange", 3000), 
                Fruit("grapefruit", 3800)
            )
        ),
        FruitSection(
            color = "red",
            fruitList = listOf(
                Fruit("berry", 3400), 
                Fruit("apple", 1600)
            )
        ),
        FruitSection(
            color = "green",
            fruitList = listOf(
                Fruit("melon", 8000), 
                Fruit("muscat", 5000)
            )
        )
    )

val mostExepensiveSection : FruitSection = fruitSections.maxBy { it.fruitList.sumOf{ it.price } }
print(mostExpensiveSection.color)
// green

리스트 자르기 slice vs subList

list.slice(from .. to)

시작 인덱스부터 끝 인덱스까지 (포함) 잘라서 새로운 서브리스트 리턴.

 

list.subList(from, to)

시작 인덱스부터 끝 인덱스까지 (미포함) 자를 때, 원본 리스트를 바라보고 있음.

 

mutableList를 조작하면서 subList()로 인덱스에 접근하면 ConcurrentModificationException이 뜬다.

var list = mutableListOf(0,1,2,3,4)
println("before :\t" + list)
    
val sliced = list.slice(0..1)
println("sliced :\t" + sliced)
    
val subListed = list.subList(0,2)
println("subListed :\t" + subListed)
println()

// mutableList 요소 재할당
list[0] = 100
    
println("after  :\t" +list) 
println("sliced :\t" + sliced)
println("subListed :\t" + subListed)
println()

// mutableList 요소 추가 / 삭제 -> ConcurrentModificationException
list.add(100)
list.removeAt(0)
    
println("after  :\t" +list) 
println("sliced :\t" + sliced)
println("subListed :\t" + subListed)

// before :	[0, 1, 2, 3, 4]
// sliced :	[0, 1]
// subListed :	[0, 1]
//
// after  :	[100, 1, 2, 3, 4]
// sliced :	[0, 1]
// subListed :	[100, 1]
//
// after  :	[1, 2, 3, 4, 100]
// sliced :	[0, 1]
// Exception in thread "main" java.util.ConcurrentModificationException

MutableList 가 아닌 List로 초기화하면,

리스트 변수에 재할당할 때 새로운 객체가 생성되기 때문에 예외가 발생하지 않는다.

var list = listOf(1,2,3,4,5)
println("before :\t" + list)
    
val sliced = list.slice(0..1)
println("sliced :\t" + sliced)
    
val subListed = list.subList(0,2)
println("subListed :\t" + subListed)

println()
list = List(5) { (0..10).random() }
    
println("after  :\t" +list) 
println("sliced :\t" + sliced)
println("subListed :\t" + subListed)

// before :	[1, 2, 3, 4, 5]
// sliced :	[1, 2]
// subListed :	[1, 2]
//
// after  :	[7, 4, 5, 2, 0]
// sliced :	[1, 2]
// subListed :	[1, 2]

 

728x90