Котлин отличается По условию - PullRequest
1 голос
/ 22 мая 2019

У меня есть массив с несколькими объектами с одним и тем же ключом, другие объекты имеют пустые значения, и я надеялся использовать DifferentBy для удаления дубликатов и получения объектов, значения которых имеют самую длинную строку.

data class ObjA(val key: String, val value: String)

fun test() {
    val listOfA = mutableListOf(
            ObjA("one", ""), //This will be taken in distinctBy.
            ObjA("one", "o"),
            ObjA("one", "on"),
            ObjA("one", "one"), //This will be ignored in distinctBy. I WANT THIS ONE.

            ObjA("two", ""), //This will be returned in distinctBy
            ObjA("two", "2"),
            ObjA("two", "two"), //But I want this.

            ObjA("three", "3"),
            ObjA("four", "4"),
            ObjA("five", "five")
    )

    val listOfAWithNoDuplicates = listOfA.distinctBy { it.key }

    for (o in listOfAWithNoDuplicates) {
        println("key: ${o.key}, value: ${o.value}")
    }
}

выход

key: one, value: 
key: two, value: 
key: three, value: 3
key: four, value: 4
key: five, value: five

Как заставить это работать. Любая помощь будет оценена.

Ответы [ 2 ]

1 голос
/ 22 мая 2019

Поскольку distinctBy просто возвращает отдельные ключи, основанные на вашем селекторе (и в порядке списка), вы получаете уникальные ключи, но еще не те значения, которые вам нужны.

Для этого конкретного варианта использования я бы, вероятно, просто отсортировал заранее, а затем distinctBy

listOfA.sortedByDescending { it.value.length }
       .distinctBy { it.key }

, который создает новый список вsortedByDescending или вы просто сортируете текущий список заранее (sortByDescending) и затем применяете distinctBy, например:

listOfA.sortByDescending { it.value.length }
listOfA.distinctBy { it.key }

В обоих случаяхВы получаете новый List<ObjA> с ожидаемыми значениями.

Несколько других вариантов приходят мне на ум.Все эти варианты помещают результаты в Map<String, ObjA>, где ключ на самом деле является уникальным ObjA.key.Возможно, вы захотите позвонить .values напрямую, если вас не интересует отображение ключа / ObjA.

  1. вариант с использованием groupingBy и reduce:

    listOfA.groupingBy { it.key }
           .reduce { _, acc, e->
             maxOf(e, acc, compareBy { it.value.length })
           }
    
  2. вариант с использованием простого forEach / for и заполнением собственного Map:

    val map = mutableMapOf<String, ObjA>()
    listOfA.forEach {
        map.merge(it.key, it) { t, u ->
            maxOf(t, u, compareBy { it.value.length })
        }
    }
    
  3. вариант с использованием fold и merge (очень похоже на предыдущий ... просто используя fold вместоfor / forEach):

    listOfA.fold(mutableMapOf<String, ObjA>()) { acc, objA ->
      acc.apply {
        merge(objA.key, objA) { t, u ->
          maxOf(t, u, compareBy { it.value.length })
        }
      }
    }
    
  4. вариант с использованием groupBy, за которым следует mapValues (но вызатем фактически создаем 1 карту, которую вы немедленно отбрасываете):

    listOfA.groupBy { it.key } // the map created at this step is discarded and all the values are remapped in the next step
           .mapValues { (_, values) ->
              values.maxBy { it.value.length }!!
           }
    
0 голосов
/ 22 мая 2019

Вы можете использовать maxBy{}, например:

val x = listOfAWithNoDuplicates.maxBy { it.key.length }
println(x)

Выход

ObjA(key=three, value=3)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...