2011-01-12 12 views
9

Este es el problema que he resuelto, sin embargo, siendo un total novato de Scala, siento que encontré algo totalmente no elegante. Cualquier idea de mejora apreciada.Scala inserta en la lista en ubicaciones específicas

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) 

Estaba pensando solución más elegante sería alcanzable con algo como esto, pero eso es sólo especulación pura.

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

Respuesta

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) 

Editar: explicación añadió.

Nuestro objetivo aquí es insertar una lista (llamada extra) delante de los elementos seleccionados en otra lista (aquí se llama xs utilizado --commonly para las listas, como si una cosa es x entonces un montón de ellos debe ser el plural xs) Queremos que esto funcione en cualquier tipo de lista que tengamos, por lo que lo anotamos con el tipo genérico [A].

¿Qué elementos son candidatos para la inserción? Al escribir la función, no lo sabemos, por lo que proporcionamos una función que dice verdadero o falso para cada elemento (p: A => Boolean).

Ahora, para cada elemento en la lista x, comprobamos: ¿deberíamos hacer la inserción (es decir, es p(x) verdadero)? En caso afirmativo, solo lo compilamos: extra ::: List(x) son solo los elementos de extra seguidos por el elemento único x. (Podría ser mejor escribir esto como extra :+ x --agregar el único elemento al final.) Si no, tenemos solo el único elemento, pero lo hacemos List(x) en lugar de solo porque queremos que todo tenga el mismo tipo. Así que ahora, si tenemos algo así como

4 1 2 3 4 

y nuestra condición es que insertamos 5 6 antes 4, generamos

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

Esto es exactamente lo que queremos, excepto que tenemos una lista de listas. Para deshacerse de las listas internas y aplanar todo en una sola lista, simplemente llamamos al flatten.

+0

Obra de arte;) ¿Qué significa la primera [A]? ¿Que significa? – Murgh

+0

El primer '[A]' significa que es un método genérico (funciona en algún tipo 'A'; los últimos 'A' se refieren a ese mismo). '_' significa" cualquiera que sea la variable "; es un atajo para 'x => x == 4'. –

+2

'xs.map (..). Flatten' se puede escribir como' xs.flatMap (..) '. – Landei

10

El truco aplanado es lindo, no hubiera pensado usar map aquí. Desde mi punto de vista, este problema es una aplicación típica para un doblez, ya que desea pasar por la lista y "recopilar" algo (la lista de resultados). Como no queremos que nuestra lista de resultados hacia atrás, foldRight (también conocido como :\) está aquí la versión correcta:

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

Aquí es otra posibilidad, por Seq#patch para manejar las inserciones reales. Es necesario doblar la derecha para que los índices posteriores se manejen primero (las inserciones modifican los índices de todos los elementos después de la inserción, de lo contrario sería complicado).

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) } 
} 
Cuestiones relacionadas