J'ai lu attentivement la documentation ArrayList dans Kotlin et apparemment il n'y a aucun moyen de rechercher une valeur dans ArrayList à partir d'un pointeur. L'alternative est d'écrire votre propre fonction en itérant les bons éléments dans ArrayList et en testant la condition.
J'ai donc programmé le code suivant:
fun <T> ArrayList<T>.findNext(cond: (T) -> Boolean, p: Int = 0): Int {
for (i in p..this.lastIndex)
if (cond(this[i])) return i
return -1
}
data class Person (
var name: String,
var age: Int
)
fun main() {
var v = arrayListOf<Person>()
v.add(Person("Paul", 22))
v.add(Person("Laura", 24))
v.add(Person("Paul", 50))
v.add(Person("Mary", 24))
println(v.findNext({it.name=="Paul"})) // 0
println(v.findNext({it.name=="Paul"}, 1)) // 2
println(v.findNext({it.name=="Paul"}, 3)) // -1
}
Y a-t-il quelque chose de mieux que ça?
3 Réponses :
peut-être utiliser withIndex et un filtre?
it.value.name == "Paul"
cela vous donnera la sortie 0 et 2
pour votre cas (objet personne au lieu de String) que vous utiliserez
val arrayNames = listOf<String>("Paul", "Ann", "Paul", "Roger","Peter")
arrayNames.withIndex().filter {
it.value == "Paul" //value contains the original name
}.forEach{
println(it.index) //indext contains the position.
}
Intéressant. Je ne connaissais pas withIndex () . Il peut également être utilisé avec des classes de données . v.withIndex (). filter {it.value.name == "Paul" // valeur contient le nom d'origine} .forEach {println (it.index) // indext contient la position. }}
fun main() {
var v = arrayListOf<Person>()
v.add(Person("Paul", 22))
v.add(Person("Laura", 24))
v.add(Person("Paul", 50))
v.add(Person("Mary", 24))
println(v.findNext({ it.name == "Paul" },0))//IndexedValue(index=0, value=Person(name=Paul, age=22))
println(v.findNext({ it.name == "Paul" },2))//IndexedValue(index=2, value=Person(name=Paul, age=50))
println(v.findNext({ it.name == "Paul" },3))//null
}
private fun <T> List<T>.findNext(cond: (T) -> Boolean, position: Int): IndexedValue<T>? {
return withIndex().filter { it.index >= position }.firstOrNull { cond(it.value) }
}
Joli! il peut être adapté pour renvoyer l'index: private fun
Oui, Int? sera meilleur que IndexedValue
Vous pouvez utiliser dropWhile au lieu de filter pour éviter un travail supplémentaire.
Vous pouvez éviter toute collection intermédiaire:
println(v.findNext {it.name=="Paul"}) // 0
println(v.findNext(1) {it.name=="Paul"}) // 2
println(v.findNext(3) {it.name=="Paul"}) // null
En échangeant les arguments, vous pouvez l'appeler comme ceci:
inline fun <T> List<T>.findNext(p: Int = 0, cond: (T) -> Boolean) =
listIterator(p).withIndex().asSequence().find { cond(it.value) }?.let { it.index + p }
Génial! Il est intéressant de noter qu'exécuter 100 000 fois cette méthode est deux fois plus rapide que la réponse motee mais a la moitié de la vitesse du code, moins élégante mais efficace, dans la question.
Oui, il doit encore allouer l'itérateur, faire des appels de méthode, etc. J'aurais dû mentionner que votre code sera plus rapide.
@Pauloedralsbaum Notez également que votre méthode et toutes les réponses peuvent être marquées inline pour éviter les allocations supplémentaires et l'indirection pour le paramètre cond (qui devra probablement être crossinline < / code>): kotlinlang.org/docs/reference/inline-functions.html a>
Je fais de la programmation scientifique, donc j'utilise beaucoup de inlines . C'est une excellente fonctionnalité Kotlin . Dans ma question, j'ai préféré le cas simple parce qu'il n'est pas lié à la question.