2011-09-12 15 views
5

Tengo una matriz 2d de tipo booleano (no importante) Es fácil de iterar sobre la matriz en estilo no funcional. ¿Cómo hacerlo estilo FP?2d iteración de matriz scala

var matrix = Array.ofDim[Boolean](5, 5) 

por ej, me gustaría recorrer todas las filas de una columna dada y devolver una lista de int que se correspondería con una función específica. Ejemplo: para la columna 3, repita las filas 1 a 5 para devolver 4, 5 si la celda en (4, 3), (5, 3) coincide con una función específica. Thx v mucho

def getChildren(nodeId: Int) : List[Int] = { 
    info("getChildren("+nodeId+")") 

    var list = List[Int]() 
    val nodeIndex = id2indexMap(nodeId) 

    for (rowIndex <- 0 until matrix.size) { 
     val elem = matrix(rowIndex)(nodeIndex) 
     if (elem) { 
     println("Row Index = " + rowIndex) 
     list = rowIndex :: list 
     } 
    } 

    list 
    } 

Respuesta

4

¿Qué hay de

(1 to 5) filter {i => predicate(matrix(i)(3))} 

donde predicate es su función?

Tenga en cuenta que inicializa con (5,5) índices va de 0 a 4.

actualización: basado en el ejemplo

def getChildren(nodeId: Int) : List[Int] = { 
    info("getChildren("+nodeId+")") 
    val nodeIndex = id2indexMap(nodeId) 

    val result = (0 until matrix.size).filter(matrix(_)(nodeIndex)).toList 
    result.forEach(println) 
    result 
} 

Es posible mover la impresión en el fiter si quieres también, y revertir la lista si lo desea exactamente como en el ejemplo

+0

Creo que su sol devolvería una matriz si la estructura inicial es una matriz de 2d? – jts

+0

Ah, otra diferencia es que estaba pensando en filtrar directamente en la matriz 2d, pero al hacerlo, estoy perdiendo el índice de la fila: val children = matrix.filter (row => row (nodeIndex)) que devuelve 2 matrices 1d - pero no sé cuál – jts

+0

No realmente, la estructura en la que hago es un Rango, no una Matriz (como lo eran los índices que quería en el salida). El tipo de resultado es IndexedSeq [Int] y resulta ser un Vector. Simplemente haz .toList si quieres una lista, pero Vector es generalmente una estructura mejor que List. –

1
def findIndices[A](aa: Array[Array[A]], pred: A => Boolean): Array[Array[Int]] = 
    aa.map(row => 
    row.zipWithIndex.collect{ 
     case (v,i) if pred(v) => i 
    } 
) 

puede refactorearlo a ser un poco más agradable mediante la extracción de la función que encuentra los índices en una única fila:

def findIndices2[A](xs: Array[A], pred: A => Boolean): Array[Int] = 
    xs.zipWithIndex.collect{ 
    case (v,i) if pred(v) => i 
    } 

y luego escribir

matrix.map(row => findIndices2(row, pred)) 
2

Si no se siente cómodo con los filtros y las cremalleras, se puede seguir con el para-comprensión, pero su uso de una manera más funcional:

for { 
    rowIndex <- matrix.indices 
    if matrix(rowIndex)(nodeIndex) 
} yield { 
    println("Row Index = " + rowIndex) 
    rowIndex 
} 

yield construye una nueva colección a partir de los resultados de la comprensión fines de, por lo que esta expresión se evalúa a la colección que desea devolver . seq.indices es un método equivalente a 0 until seq.size. Las llaves le permiten abarcar varias líneas sin punto y coma, pero se puede hacer en línea si desea:

for (rowIndex <- matrix.indices; if matrix(rowIndex)(nodeIndex)) yield rowIndex 

probablemente debería también mencionar que normalmente si estás iteración a través de una matriz no será necesario para referirse a los índices en absoluto. Harías algo así como

for { 
    row <- matrix 
    elem <- row 
} yield f(elem) 

pero tu caso de uso es un poco inusual, ya que requiere que los índices de los elementos, que no se debe normalmente ser referido a (usando los índices de matriz es esencialmente una rápida y sucio hack para emparejar un elemento de datos con un número). Si desea capturar y usar la noción de posición, es mejor que use un Map[Int, Boolean] o un case class con un campo de este tipo.