Как лучше всего найти элемент в вложенных списках?

Kotlin предоставляет некоторые полезные функции расширения, позволяющие потоковое программирование.

Например, если я ищу элемент в списке, я могу использовать find :

 return list.find { n -> n>4 && n<6 } 

Но когда у меня есть вложенные списки, это кажется мне непрактичным. Тогда я использую forEach – к счастью, я могу вернуться из внутренней Лямбды с Котлином:

 private fun findUsingForEach(data: List<List<Int>>, pred : (Int) -> Boolean) : Optional<Int> { data.forEach { list -> list.forEach { n -> if( pred(n) ) return Optional.of(n) } } return Optional.empty() } 

Мне кажется, что forEach не подходит для этого. Есть ли более функциональный способ этого? filter приходит на ум, но вложенность вызывает проблемы.

Этот результат – это тест, который я использую для функции abouve:

 @Test open fun findTest() { val data = listOf( listOf(1,2,3), listOf(3,4,5,6), listOf(), listOf(6,7,8) ) val e = findUsingForEach( data, { n -> n>4 && n < 6 } ) assertEquals(5, e.get()) } 

Вы можете flatten список:

fun <T> Iterable<Iterable<T>>.flatten(): List<T> ( source )

Возвращает единственный список всех элементов из всех коллекций в данной коллекции.

 val data = listOf(listOf(1, 2, 3), listOf(3, 4, 5, 6), listOf(), listOf(6, 7, 8)) data.flatten().find { n -> n > 4 && n < 6 } 

Это вернет единый список с элементами подписок в порядке. Затем вы можете использовать find как обычно.

В вашем примере,

 {{1, 2, 3}, {3, 4, 5, 6}, {}, {6, 7, 8}} 

становится

 {1, 2, 3, 3, 4, 5, 6, 6, 7, 8} 

и результат find в этом списке равен 5 .

Однако это создаст новый список. Взгляните на источник flatten :

 /** * Returns a single list of all elements from all collections in the given collection. */ public fun <T> Iterable<Iterable<T>>.flatten(): List<T> { val result = ArrayList<T>() for (element in this) { result.addAll(element) } return result } 

Если вы хотите сохранить память, сначала создайте Sequence из списка:

 data.asSequence() 

а затем выполните следующие действия:

 data.asSequence().flatten().find { n -> n > 4 && n < 6 } 

Боковое примечание: ваш предикат n > 4 && n < 6 , просто эквивалентен n == 5 .

Если вы просто хотите уменьшить количество кодов, и вы не очень заботитесь об эффективности, попробуйте это.

 list.flatten().find { your pred here } 

Или

 list.flatMap { it }.find { your pred } 

Или создайте полезную утилиту, которая не создает новые списки (более быстрая / более низкая память):

 inline fun <T> Iterable<Iterable<T>>.forEachEach(f: (T) -> Unit) = forEach { it.forEach(f) } 
Intereting Posts
Как получить и найти текущее состояние на машине состояния Spring? Каковы преимущества сопутствующего объекта над простым объектом? Android Kotlin создает реализацию класса Parcelable дает ошибку в «переопределении» метода writeToParcel Локаторы подресурсов в Kotlin / Dropwizard AppCompatActivity, ViewModel и привязка данных Почему я получаю: null не может быть применен к непустому типу android.widget.SearchView? Каков правильный синтаксис для переопределения функции члена интерфейса с помощью модификатора видимости? Ошибка компиляции Котлина: ни одна из следующих функций не может быть вызвана с предоставленными аргументами Как установить ширину границы FloatingActionButton с Anko Какой самый элегантный способ удалить слушателя из списка из обратного вызова Получена неразрешенная ссылка: setText при преобразовании java в kotlin Android: специальный календарь Java / Kotlin Calendar Lint сбой на классе Java, читающий объект Kotlin Как я могу получить перечисление Kotlin одинакового поведения как cpp Как создать javadoc jar для загрузки репозитория с помощью dokka?