2009-05-21 9 views
6

Sé que la función de mapa toma cada elemento de una lista (una secuencia) y le aplica una función. De forma recursiva (y sin respeto a las condiciones de terminación, etc)Mapeo sobre sublistas en Scala

map(s, f) = f(s.head) :: map(s.tail, f) 

Busco a una función que hace algo como

foo(s, f) = f(s) :: map(s.tail, f). 

lo tanto un 'asignador', donde la función de mapeo es llamado en sublistas y no elementos individuales. En términos de ceceo, estoy buscando una lista de mapas, a diferencia de un carro de mapa. ¿Existe algo como esto, o tengo que hacer mi propio (o usar recursividad)?

Por otra parte, me gustaría tener una función que toma como entrada una secuencia y devuelve una secuencia de subsecuencias a mediados y finales, es decir

bar(s, f) = s :: bar(s.tail, f) 
+0

¿Puede dar un ejemplo de la entrada y la salida deseada? Tengo problemas para seguir. –

+0

No conozco la respuesta a esta pregunta, pero si necesita tipos y funciones avanzadas, consulte la biblioteca de Scalaz: http://code.google.com/p/scalaz/ – egaga

Respuesta

5

/* Este enfoque define mapList en términos de otro método útil llamado colas. Como Daniel, lo voy a poner en una extensión implícita a la lista, pero eso es puramente una cuestión de gusto */

implicit def richerList[A](list : List[A]) = new { 

/* Aquí hay un método llamado colas que devuelve cada posible de la cola de la lista. Es cola recursiva por lo que no explotará en listas grandes. Tenga en cuenta que difiere ligeramente de una función Haskell del mismo nombre. La versión Haskell siempre añade una lista vacía en la que el resultado */

def tails : List[List[A]] = { 
    def loop(ls : List[A], accum : List[List[A]]) : List[List[A]] = ls match { 
     case _ :: tail => loop(tail, ls :: accum) 
     case _ => accum 
    } 

    loop(list, Nil).reverse 
    } 

/* Esto es lo que el uso de colas se parece

scala> "abc".toList.tails 
res0: List[List[Char]] = List(List(a, b, c), List(b, c), List(c)) 

*/

/* Ahora podemos definir lista de mapas sobre la base de la cola */

def mapList[B](f : List[A] => B) = tails map f 
} 

/* Y esto es lo que el uso de lista de mapas parece

scala> "abc".toList mapList (_.reverse.mkString) 
res1: List[String] = List(cba, cb, c) 

*/

2

Es, básicamente, ha definido lo que estás buscando en pseudocódigo - por lo que es fácil de agregar un procedimiento de este tipo a una lista Scala utilizando las conversiones implícitas:

object ExtendedList{ 
    implicit def List2ExtendedList[A](l:List[A])=new ExtendedList(l) 
} 
class ExtendedList[A](l:List[A]){ 
    import ExtendedList._ 
    def mapList[B](f:List[A]=>B):List[B]=l.length match { 
    case 0 => List() 
    case _ => f(l)::l.tail.mapList(f) 
    } 
} 

object Test extends Application{ 
    import ExtendedList._ 
    val test = List(5,4,3,2,1) 
    assert(List(15,10,6,3,1)==test.mapList{l=>(0/:l){_+_}}) 
} 

es esto lo que está buscando?

+0

Es O (n) para obtener el longitud de una lista y mapList lo hace n veces, por O (n^2) costo. Ejecute esto en una lista larga y estará esperando un momento :-) –

+0

La razón por la que pregunté es que soy nuevo en Scala y quería saber si había una función canónica incorporada (para hacer que mi código fuera más legible para otros). Alternativamente, quería escuchar "no hagas eso, la forma scala de hacerlo es ___" – bsdfish

+0

Sí, reconozco que usar .length es malo, ¡debería haberlo pensado más! –

1

La otra respuesta es estrecha, pero debe Nunca uso List#length menos que sea absolutamente necesario. En particular, hace que su solución O (n^2) cuando el problema es inherentemente O (n). He aquí una versión limpia-up:

implicit def addListSyntax[A](list: List[A]) = new { 
    def mapList[B](f: List[A]=>B) = { 
    // use inner function to avoid repeated conversions 
    def loop(list: List[A]): List[B] = list match { 
     case ls @ (_ :: tail) => f(ls) :: loop(tail) 
     case Nil => Nil 
    } 

    loop(list) 
    } 
} 

Y, para responder a su pregunta original: no, no hay manera de hacer esto utilizando métodos de utilidad estándar. De hecho, tengo curiosidad por saber por qué querrías algo como esto ...

+1

Tenga cuidado aquí ya que esta versión no es recursiva de cola. Las listas grandes provocarán la explosión de la pila. –

+0

De hecho, eso es un gran error. – egaga

+0

Tengo una lista de sellos de tiempo ordenados, y necesito hacer un mapa de cosas como - cada marca de tiempo y las marcas de tiempo anteriores - cada marca de tiempo, junto con todas las marcas de tiempo durante x minutos anteriores. De nuevo, sé exactamente cómo codificarlo de múltiples maneras (al definir mi propia mapList, de manera imperativa, usando el mapa y luego filtrar adentro para generar el historial, etc.) pero quería averiguar cómo hacerlo limpiamente y la Scala camino. – bsdfish