Hayk Mkrtchyan
Hayk Mkrtchyan

Reputation: 3255

What does this distinctBy method?

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

Answers (3)

Nikola Despotoski
Nikola Despotoski

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

Nongthonbam Tonthoi
Nongthonbam Tonthoi

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

AlexT
AlexT

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

Related Questions