Reputation: 3255
I'm learning Kotlin
. Help me understand one moment. As I know distinct
returns only unique values. So if we have the same value twice or more, it will return only one time. Correct me if I'm wrong.
But what does this distinctBy
method? As I understand it has to return unique values according to my predicate.
I have code like this:
fun main() {
val myList = listOf(5, 2, 9, 12, 5, 2)
myList.distinctBy { it > 10 }.forEach { println(it) }
So it has to return 12 imho, but I'm getting an output: 5, 12. But why?
Upvotes: 1
Views: 699
Reputation: 50548
distinctBy
is using selector against objects in the list will be distinguished. This is rarely used for primitives. In your case, creates two-keys map, for keys true and false, and only first two values will be mapped.
I presume you want to filter out all numbers greater than 10, you must use .filter { it > 10 }
instead.
Upvotes: 2
Reputation: 12953
Returns a list containing only elements from the given collection having distinct keys returned by the given [selector] function.
You are getting 5 12
as output because what you have done is similar to:
val myList = listOf(5, 2, 9, 12, 5, 2)
val set = HashSet<Boolean>()
val list = ArrayList<Int>()
for (e in myList) {
if (set.add(e>10)) {
list.add(e)
}
}
list.forEach { println(it) }
Upvotes: 1
Reputation: 2964
distinctBy
takes a selector, not a predicate. It is usually used for objects, where you want a distinct based on a particular field. An example:
fun main() {
val list = listOf(
Pojo(1, "abc"),
Pojo(2, "xyz"),
Pojo(1, "hello"),
Pojo(1, "world")
)
list.distinctBy { it.fizz }.forEach { println(it) }
}
data class Pojo(
val fizz: Int,
val buzz: String
)
This will return a distinct on the fizz
property.
Pojo(fizz=1, buzz=abc)
Pojo(fizz=2, buzz=xyz)
If you want to use a predicate, you should use something like filter
.
val myList = listOf(5, 2, 9, 12, 5, 2, 13, 12)
myList.filter { it > 10 }.forEach { println(it) }
This will print:
12
13
12
As you can see, filter
will not give you an unique list. You can do that by calling toSet()
on your list before the filter (and it will still be a List
after the filter). Or by calling distinct()
after the filter. The distinct()
will actually just create a Set
and turn it back on into a List
, so I'd suggest to just use toSet()
before the filter.
Upvotes: 3