Kotlin DifferentBy с условием

У меня есть массив с несколькими объектами с одним и тем же ключом. Другие объекты имеют пустые значения, и я надеялся использовать 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

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

3 метода стилизации элементов HTML
3 метода стилизации элементов HTML
Когда дело доходит до применения какого-либо стиля к нашему HTML, существует три подхода: встроенный, внутренний и внешний. Предпочтительным обычно...
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
6
0
5 129
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

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

Выход

ObjA(key=three, value=3)

удалит ли maxBy дубликаты?

Nux 22.05.2019 12:51

Спасибо за ответ, но я думаю, что это вернет один объект с наибольшей длиной. Что я хочу, так это новый массив объектов, значения которых будут иметь максимальную длину и, конечно же, с удаленными дубликатами!

Nux 22.05.2019 12:58

Ах хорошо. неправильно понятый :)

P.Juni 22.05.2019 13:06
Ответ принят как подходящий

Поскольку 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 }!!
           }
    

Спасибо, это сработало. Можете ли вы взглянуть на это тоже. Я хочу обработать этот список еще раз stackoverflow.com/questions/56255964/…

Nux 22.05.2019 14:04

Другие вопросы по теме