val items = listOf(1, 2, 3, 4, 5)
// actual sum of 15

이와 같은 collection에서 전체 합을 구해보기.

 

1. foreach

@Test
fun sumTest_1() {
    var total = 0
    items.forEach {
        total += it
    }
    Assert.assertEquals(total, actual)
}
/**
 * Performs the given [action] on each element.
 */
@kotlin.internal.HidesMembers
public inline fun <T> Iterable<T>.forEach(action: (T) -> Unit): Unit {
    for (element in this) action(element)
}

 

가장 무난하게 많이??이들 사용했을것 같은 부분.

 

 

2. sum()

@Test
fun sumTest_2() {
    val total = items.sum()
    Assert.assertEquals(total, actual)
}
/**
 * Returns the sum of all elements in the collection.
 */
@kotlin.jvm.JvmName("sumOfInt")
public fun Iterable<Int>.sum(): Int {
    var sum: Int = 0
    for (element in this) {
        sum += element
    }
    return sum
}

각 element들의 합계를 바로 구한다. foreach의 내용이 바로 sum의 내용과 같음.

 

 

3. reduce

@Test
fun sumTest_3() {
    val total = items.reduce { acc, i -> acc + i }
    Assert.assertEquals(total, actual)
}
/**
 * Accumulates value starting with the first element and applying [operation] from left to right to current accumulator value and each element.
 * 
 * @sample samples.collections.Collections.Aggregates.reduce
 */
public inline fun <S, T : S> Iterable<T>.reduce(operation: (acc: S, T) -> S): S {
    val iterator = this.iterator()
    if (!iterator.hasNext()) throw UnsupportedOperationException("Empty collection can't be reduced.")
    var accumulator: S = iterator.next()
    while (iterator.hasNext()) {
        accumulator = operation(accumulator, iterator.next())
    }
    return accumulator
}

첫번째 element가 기본값으로 operation의 block내용을 가져와서 합계를 구함. 

 

 

4. fold

@Test
fun sumTest_4() {
    val total = items.fold(0) { acc, i ->
        acc + i
    }
    Assert.assertEquals(total, actual)
}
/**
 * Accumulates value starting with [initial] value and applying [operation] from left to right to current accumulator value and each element.
 */
public inline fun <T, R> Iterable<T>.fold(initial: R, operation: (acc: R, T) -> R): R {
    var accumulator = initial
    for (element in this) accumulator = operation(accumulator, element)
    return accumulator
}

reduce와의 차이는 초기값을 지정할 수 있음.

Collection과 Sequence는 둘다 lambda의 확장함수( map, filter, find... )를 사용하여 원하는 결과를 찾아나갈 수 있습니다.

그런데 Collection의 확장함수를 사용하면, inline function을 통해서 매번 결과가 새롭게 만들어 집니다.

public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {
    return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)
}

하지만 Sequence는 inline function이 아닌 chain call 을 통해서 결과를 이어 나갈 수 있습니다.

public fun <T, R> Sequence<T>.map(transform: (T) -> R): Sequence<R> {
    return TransformingSequence(this, transform)
}

 

같은 결과이지만, 중간 과정에서 결과를 보면,

val items = mutableListOf(1, 2, 3, 4, 5)
val result = items.map {
    it * it
}.filter {
    it % 2 == 0
}

map에서 새로운 1,4,9,16,25 가 만들어진 뒤, filter에서 새로운 4, 16의 결과만 만들지게 됩니다.

 

하지만 sequence는,

val items = mutableListOf(1, 2, 3, 4, 5)
val result = items.asSequence().map {
    it * it
}.filter {
    it % 2 == 0
}.toList()

1,1,2,4,3,9,4,16,5,25 의 순서로, 새로운 결과를 만들어지는게 아니라, 하나씩 확인을 해갑니다.

 

 

Collection에서 새로운 결과를 계속 만들다 보면 memory사용도 많아지게 되지만, Sequence로 하게 되면, 메모리 문제는 Collection보다는 덜 하게 됩니다.

+ Recent posts