¿Cuál es la mejor manera de encontrar un elemento en las lists anidadas?

Kotlin proporciona algunas funciones útiles de extensión que permiten la progtwigción tipo secuencia.

Por ejemplo, si busco un elemento en una list, puedo usar find :

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

Pero cuando tengo una list anidada, esto no me parece práctico. Lo he usado para forEach una de las siguientes: afortunadamente puedo regresar de un Lambda interno con Kotlin:

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

Me parece que forEach no es la herramienta adecuada para eso. ¿Hay una forma más funcional de hacer esto? filter viene a la mente, pero la anidación causa problemas.

Ese siguiente es la testing que uso para la function en set:

 @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()) } 

    Podría flatten la list:

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

    Devuelve una list única de todos los elementos de todas las collections en la colección dada.

     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 } 

    Esto devolverá una list única con los elementos de las sublists en order. Entonces puedes usar find como de costumbre.

    En tu ejemplo,

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

    se convierte

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

    y el resultado de find en esta list es 5 .

    Sin embargo, esto creará una nueva list. Echa un vistazo a la fuente de 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 } 

    Si desea save memory, primero cree una Sequence de su list:

     data.asSequence() 

    y luego realiza tus operaciones en esta secuencia:

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

    Nota al margen: su pnetworkingicado, n > 4 && n < 6 , es simplemente equivalente a n == 5 .

    Si solo quiere networkingucir los códigos y no le importa demasiado la eficiencia, intente esto.

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

    O

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

    O cree una utilidad útil que no cree lists nuevas (más rápido / less memory):

     inline fun <T> Iterable<Iterable<T>>.forEachEach(f: (T) -> Unit) = forEach { it.forEach(f) }