2011-01-12 14 views
9

Questo è il problema che ho risolto, tuttavia essendo un imperativo di Scala noob totale, sento di aver trovato qualcosa di totalmente non elegante. Qualche idea di miglioramento apprezzabile.Scala inserire nell'elenco in posizioni specifiche

val l1 = 4 :: 1 :: 2 :: 3 :: 4 :: Nil // original list 
val insert = List(88,99) // list I want to insert on certain places 

// method that finds all indexes of a particular element in a particular list 
def indexesOf(element:Any, inList:List[Any]) = { 
     var indexes = List[Int]() 
     for(i <- 0 until inList.length) { 
       if(inList(i) == element) indexes = indexes :+ i 
     } 
     indexes 
} 


var indexes = indexesOf(4, l1) // get indexes where 4 appears in the original list 

println(indexes) 

var result = List[Any]() 

// iterate through indexes and insert in front 
for(i <- 0 until indexes.length) { 
     var prev = if(i == 0) 0 else indexes(i-1) 
     result = result ::: l1.slice(prev, indexes(i)) ::: insert 
} 
result = result ::: l1.drop(indexes.last) // append the last bit from original list 

println(result) 

pensavo soluzione più elegante sarebbe realizzabile con qualcosa di simile, ma questa è solo pura speculazione.

var final:List[Any] = (0 /: indexes) {(final, i) => final ::: ins ::: l1.slice(i, indexes(i)) 

risposta

14
def insert[A](xs: List[A], extra: List[A])(p: A => Boolean) = { 
    xs.map(x => if (p(x)) extra ::: List(x) else List(x)).flatten 
} 

scala> insert(List(4,1,2,3,4),List(88,99)){_ == 4} 
res3: List[Int] = List(88, 99, 4, 1, 2, 3, 88, 99, 4) 

Edit: spiegazione aggiunto.

Il nostro obiettivo è quello di inserire una lista (chiamato extra) di fronte a elementi selezionati in un altro elenco (qui chiamato xs --commonly utilizzato per gli elenchi, come se una cosa è x poi un sacco di loro deve essere il plurale xs). Vogliamo che funzioni su qualsiasi tipo di elenco che potremmo avere, quindi lo annotiamo con il tipo generico [A].

Quali elementi sono candidati per l'inserimento? Quando scriviamo la funzione, non lo sappiamo, quindi forniamo una funzione che dice true o false per ogni elemento (p: A => Boolean).

Ora, per ciascun elemento nell'elenco x, verifichiamo - dovremmo effettuare l'inserimento (vale a dire p(x) true)? Se sì, lo costruiamo semplicemente: extra ::: List(x) è solo gli elementi di extra seguito dall'elemento singolo x. (Potrebbe essere meglio scrivere questo come extra :+ x - aggiungere il singolo oggetto alla fine.) Se no, abbiamo solo il singolo elemento, ma lo facciamo List(x) invece di solo x perché vogliamo che tutto abbia lo stesso tipo. Così ora, se abbiamo qualcosa di simile

4 1 2 3 4 

e la nostra condizione è che noi inseriamo 5 6 prima 4, abbiamo generare

List(5 6 4) List(1) List(2) List(3) List(5 6 4) 

Questo è esattamente quello che vogliamo, tranne che abbiamo una lista di liste. Per sbarazzarsi delle liste interne e appiattire tutto in un'unica lista, chiamiamo semplicemente flatten.

+0

Opera d'arte;) Che cosa significa la prima [A]? Cosa significa? – Murgh

+0

Il primo '[A]' significa che si tratta di un metodo generico (funziona su alcuni tipi 'A', i successivi' A' si riferiscono a quello stesso). '_' significa" qualunque sia la variabile "; è una scorciatoia per 'x => x == 4'. –

+2

'xs.map (..). Flatten' può essere scritto come' xs.flatMap (..) '. – Landei

10

Il trucco piatto è carino, non avrei pensato di utilizzare map qui da solo. Dal mio punto di vista, questo problema è una tipica applicazione per una piega, dato che vuoi passare attraverso la lista e "raccogliere" qualcosa (la lista dei risultati). Poiché non vogliamo che la nostra lista dei risultati all'indietro, foldRight (pseudonimo :\) è qui la versione corretta:

def insert[A](xs: List[A], extra: List[A])(p: A => Boolean) = 
    xs.foldRight(List[A]())((x,xs) => if (p(x)) extra ::: (x :: xs) else x :: xs) 
3

Ecco un'altra possibilità, utilizzando Seq#patch per gestire gli inserti effettivi. Devi foldare in modo che gli indici successivi vengano gestiti per primi (gli inserti modificano gli indici di tutti gli elementi dopo l'inserimento, altrimenti sarebbe complicato altrimenti).

def insert[A](xs: Seq[A], ys: Seq[A])(pred: A => Boolean) = { 
    val positions = xs.zipWithIndex filter(x => pred(x._1)) map(_._2) 
    positions.foldRight(xs) { (pos, xs) => xs patch (pos, ys, 0) } 
} 
Problemi correlati