2017-06-28 3 views
2

Angenommen, ich habe zwei Listen von Objekten, die beide eine Schnittstelle implementieren, aber ansonsten nichts miteinander zu tun haben. Wie kann ich eine neue Sammlung von Objekten erstellen, die nur die Objekte einer der Listen enthalten, die mit einem Wert in der anderen Liste übereinstimmen? Natürlich könnte ich eine for-Schleife verwenden & tun dies manuell, aber ich würde gerne wissen, wie ich dies mit Kotlins Standardbibliothek Sammlung Filterfunktionen tun kann. Ich habe die Dokumentation gelesen, und ich bin mir ziemlich sicher, dass ich filterTo verwenden muss, aber ich bin mir nicht sicher, wie ich die Prädikate oder Transformationen festlegen soll, und ich kenne Kotlin noch nicht genug, um den Dokumenten viel Sinn zu geben .Erstellen Sie eine neue Liste aus zwei anderen Listen unterschiedlicher Typen, indem Sie die Werte der einzelnen Typen vergleichen.

ich ein bisschen eine harte Zeit habe genau herauszufinden, wie zu setzen, was ich möchte in einem Absatz zu erreichen, die Sinn macht, also hier ein Beispiel:

interface Ids 
{ 
    val id: Int 
} 

data class A(override val id: Int, val name: String) : Ids 
data class B(override val id: Int, val timestamp: Long) : Ids 

fun main(args: Array<String>) { 
    val a1 = A(1, "Steve") 
    val a2 = A(2, "Ed") 
    val aCol = listOf(a1, a2) 

    val b2 = B(2, 12345) 
    val b3 = B(3, 67890) 
    val bCol = listOf(b2, b3) 

    val matches = mutableListOf<B>() 
    // This is where I'm stuck. 
    // I want to filter bCol using objects from aCol as a filter. 
    // The result should be that matches contains only a single object: b2 
    // because bCol[0].id == aCol[1].id 
    // I'm guessing I need to start with something like this: 
    bCol.filterTo(matches) { ??? } 
} 

Antwort

4

Ein einfacher Ansatz wäre seine aCol für jeden b in bCol mit derselben ID für ein Objekt zu suchen:

bCol.filter { b -> aCol.any { a -> a.id == b.id } } 

jedoch die zu langsam werden können, wenn Ihre Listen groß genug sind.

Um es skalierbarer Sie zuerst eine Menge aller ids in aCol bauen können:

val aColIds = aCol.map { it.id }.toSet() 

Und dann verwenden Set.contains Methode, um zu bestimmen, ob b.id ist in aColIds:

bCol.filter { it.id in aColIds } 
// or equivalent 
bCol.filter { aColIds.contains(it.id) } 
+1

ich liquidiert Das zu tun, was ich wollte: 'bCol.filterTo (Übereinstimmungen) {aCol.map {it.id} .enthält (it.id)}'. Irgendeine Idee darüber, wie sich das auf die Leistung im Vergleich zur Antwort auswirkt? In diesem speziellen Fall werde ich niemals einen schrecklich großen Datensatz haben (<= 128 Elemente). –

+1

@JordanBondo Das ist sogar langsamer als der erste Ansatz, da 'aCol.map' für jedes Element in' bCol' aufgerufen wird und dann das Ergebnis verworfen wird. Dies erhöht nicht nur die Komplexität der Berechnungen, sondern verursacht auch erhebliche Speicherkosten. – Ilya

+0

Für jeden, der darüber stolperte, habe ich einige Tests mit großen (1mil) und kleinen (256) Datensätzen durchgeführt und festgestellt, dass @ Ilyas Lösung tatsächlich VIEL schneller ist als meine, wobei "filterTo" anstatt "filter" auch eine hatte signifikante Leistungsverbesserung. –

Verwandte Themen