2016-03-04 11 views
12

Sto cercando di trovare una funzione di coda in List<T> ma non sono riuscito a trovarne. Ho finito per fare questo.Kotlin List tail function

fun <T> List<T>.tail() = this.takeLast(this.size -1) 

C'è un modo migliore per farlo?

risposta

22

Kotlin non ha una funzione integrata List<T>.tail(), quindi l'implementazione della propria funzione di estensione è l'unico modo. Anche se l'implementazione è perfettamente bene, può essere semplificato un po ':

fun <T> List<T>.tail() = drop(1) 

Oppure, invece di funzione di estensione, è possibile definire una proprietà di estensione:

val <T> List<T>.tail: List<T> 
    get() = drop(1) 

val <T> List<T>.head: T 
    get() = first() 

E poi utilizzarlo come:

+5

Se si dispone di un caso in cui non si desidera copiare l'elenco (che va bene in molti casi, la cache della CPU e gli elenchi più piccoli vanno bene) quindi guardare lo standard Java 'sottolista' per una variante dell'estensione https://docs.oracle.com/javase/7/docs/api/java/util/List.html#subList(int,%20int) (come per @hotkey in un commento qui sotto) –

3

Le vostre soluzioni e @Vladimir Mironov saranno funzionano, ma creano automaticamente copie desiderose della lista originale (senza il primo elem ent), che può richiedere molto tempo per le liste più grandi. Lo definirei con un wrapper List classe che delega i suoi metodi alla avvolto uno, ignorando il primo elemento con adeguamenti dell'indice:

private class TailList<T> (private val list: List<T>) : List<T> { 
    override val size: Int 
     get() = list.size -1 

    override fun isEmpty(): Boolean = size == 0 

    override fun iterator(): Iterator<T> = listIterator() 
    override fun listIterator(): ListIterator<T> = list.listIterator(1) 
    override fun listIterator(index: Int): ListIterator<T> = list.listIterator(index + 1) 
    override fun subList(fromIndex: Int, toIndex: Int): List<T> = list.subList(fromIndex + 1, toIndex + 1) 
    override fun lastIndexOf(element: T): Int = list.lastIndexOf(element) - 1 
    override operator fun get(index: Int): T = list[index + 1] 

    // The following member functions require the copy of a new list 
    override fun containsAll(elements: Collection<T>): Boolean = tailList.containsAll(elements) 
    override fun contains(element: T): Boolean = tailList.contains(element) 
    override fun indexOf(element: T): Int = tailList.indexOf(element) 

    private val tailList by lazy { ArrayList(this) } // makes a proper copy the elements this list represents 
} 

Si possono notare le funzioni della sezione dopo il commento finiscono comunque per fare un ansioso copia. L'ho fatto solo per ragioni di semplicità. Per memoria, ho creato una proprietà

Potrebbero essere tutti implementati iterando sulla raccolta manualmente, piuttosto che fare una sorta di delega. Se è quello che preferisci, sono sicuro che puoi capirlo.

Con questo, le proprietà testa e di coda diventano questo:

val <T> List<T>.tail: List<T> 
    get() = 
     if(this.isEmpty()) 
      throw IllegalStateException("Cannot get the tail of an empty List") 
     else 
      TailList(this) 

val <T> List<T>.head: T 
    get() = this[0] // or first() 

Se si ha realmente bisogno, posso aggiungere un aggiornamento per fare gli ultimi tre funzioni membro in modo che essi non fanno copie desiderosi.

EDIT: Nota: Se avete seguito le convenzioni che Kotlin ha seguito finora, non si farebbe la coda 's il List essere pigro, come questo, dal momento che tutte le loro funzioni List eseguire copie desiderosi. Invece, specialmente se stai utilizzando head e tail per scorrere iterativamente in modo ricorsivo su un elenco, vedrei se potresti provare questa idea di wrapper su Sequence in qualche modo. Sequence L'intero punto di esistenza è per il lavoro pigro sulle raccolte.

MODIFICA 2: Apparentemente sottolista() crea una vista ed è quindi già pigro. In sostanza, ti ho appena insegnato come creare l'implementazione per il sottolista, tranne che l'ho ristretto solo alla coda.

Quindi, in tal caso basta usare la funzione di sottolista() per la funzione di coda.

+1

Perché non usare semplicemente 'sottolista 'di Java?Fa esattamente la stessa cosa, crea una vista della lista originale. https://docs.oracle.com/javase/7/docs/api/java/util/List.html#subList(int,%20int) – hotkey

+0

Non è questo il significato delle sequenze? –

+1

@hotkey Non ho capito che le sottoliste erano viste. Buono a sapersi. –