Reputation: 3002
I'm trying to filter certain items out of a list and merge them in the final list in a specific order. The first code snippet seems inefficient since it creates 2 lists for filtering & then iterates over them however that code works. The second snippet is trying to combine both filterings however the map operator is not adding items to otherNums list
Could someone please help me understand why is this happening?
Snippet 1:
fun main() {
val favItem = 0
val list = listOf(11, 12, 13, 2,3,4,5,6,7,10, favItem)
val greaterThan10 = list.filter{item -> item > 10}
val otherNums = list.asSequence().filter{item -> item != favItem}.filter{item -> item < 10}
println(" $greaterThan10") //the list is filled with proper numbers
println("merged list ${greaterThan10.plus(favItem).plus(otherNums)}")
}
Result:
[11, 12, 13]
merged list [11, 12, 13, 0, 2, 3, 4, 5, 6, 7]
Snippet 2:
fun main() {
val favItem = 0
val list = listOf(11, 12, 13, 2,3,4,5,6,7,10, favItem)
val greaterThan10 = mutableListOf<Int>()
val otherNums = list.asSequence().filter{item -> item != favItem}.map{
if(it > 10) {
greaterThan10.add(it)
}
it
}
.filter{item -> item != 10}
println("$greaterThan10") // the list is empty
println("merged list ${greaterThan10.plus(favItem).plus(otherNums)}")
}
Result:
[]
merged list [0, 11, 12, 13, 2, 3, 4, 5, 6, 7]
Upvotes: 3
Views: 582
Reputation: 10493
In your second snippet, greaterThan10
list is empty because of the lazy behavior of sequences, a sequence is iterated only when a terminal operation is encountered like toList()
or sum()
.
In your case, the sequence is iterated when you write .plus(otherNums)
. List
+ Sequence
produces a List
. If you print your greaterThan10
list after printing the merged list, you will find it populated.
Btw, you don't need a Sequence
here. Two major cases where sequences are more performant than lists are:
map
, filter
etc.
With Iterable
a lot of intermediate Iterable
s are created which consume more memory,take()
, contains()
, first()
etc. i.e. when the entire collection needs not be iterated to get the final result.As per the docs,
The lazy nature of sequences adds some overhead which may be significant when processing smaller collections or doing simpler computations. Hence, you should consider both Sequence and Iterable and decide which one is better for your case.
For the final solution, I think you can use your snippet 1. That looks good to me, just remove the unnecessary asSequence
and combine the two filter
into one.
fun main() {
val favItem = 0
val list = listOf(11, 12, 13, 2, 3, 4, 5, 6, 7, 10, favItem)
val greaterThan10 = list.filter {item -> item > 10}
val otherNums = list.filter { it != favItem && it <= 10 }
println(" $greaterThan10")
println("merged list ${greaterThan10 + favItem + otherNums}")
}
I think using filter
is better than minus
on lists as the latter has quadratic worst case time complexity (if I remember correctly).
I wrote a small example to demonstrate the difference. Run this a few times to see the difference.
Also, as @IvoBeckers mentioned in the comment, "If the original list doesn't have a favItem this method will also add one to it. And if the list has multiple of the favItem this method will replace it with a single one."
Upvotes: 2
Reputation: 7163
val favItem = 0
val list = listOf(11, 12, 13, 2, 3, 4, 5, 6, 7, 10, favItem)
val (greaterThan10, otherNums) = list // destructuring assignment
.filter { it != favItem } // filter out favItem
.groupBy { it > 10 } // create two groups
.toSortedMap { o1, _ -> if (o1) -1 else 1 } // sort groups in the order [true, false]
.map { it.value.toList() } // return the two lists
println("greaterThan10: $greaterThan10")
println("otherNums: $otherNums")
println("merged list: ${greaterThan10 + favItem + otherNums}")
Upvotes: 0
Reputation: 7163
val favItem = 0
val list = listOf(11, 12, 13, 2, 3, 4, 5, 6, 7, 10, favItem)
val greaterThan10 = list.filter { it > 10 }
val otherNums = list - greaterThan10.toSet() - favItem
println("greaterThan10: $greaterThan10") // [11, 12, 13]
println("otherNums: $otherNums") // [2, 3, 4, 5, 6, 7, 10]
println("merged list: ${greaterThan10 + favItem + otherNums}")
Edit: replaced .minus(...) with -. Thanks to @Ivo Beckers' comment.
Upvotes: 0