2011-09-12 19 views
5

Ho una matrice 2d di tipo booleano (non importante) È facile iterare sull'array in stile non funzionale. Come si fa in stile FP?iterazione array scala 2d

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

per ex, vorrei per scorrere tutte le righe per una determinata colonna e restituire un elenco di int che sarebbe partita una funzione specifica. Esempio: per la colonna 3, scorrere le righe da 1 a 5 per restituire 4, 5 se la cella in (4, 3), (5, 3) corrisponde a una funzione specifica. Thx v molto

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 
    } 

risposta

4

Che dire

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

dove predicate è la vostra funzione?

noti che inizializzato con (5,5) gli indici va da 0 a 4.

Aggiornamento: sulla base di vostro esempio

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 
} 

Si può spostare la stampa nella fiter se si desidera anche, e invertire la lista se si vuole esattamente come nel tuo esempio

+0

Penso che il tuo sol restituirà un array se la struttura iniziale è un array 2d? – jts

+0

Ah, un'altra differenza è che stavo pensando di filtrare direttamente sull'array 2d, ma così facendo, sto perdendo l'indice di riga: val children = matrix.filter (row => row (nodeIndex)) che restituisce 2 array 1d - ma non so quale sia – jts

+0

In realtà, la struttura su cui fingo è un Range, non una Array (come lo erano gli indici che si desideravano nel produzione). Il tipo di risultato è un IndexedSeq [Int] e sembra essere un vettore. Basta fare .toList se si desidera una lista, ma Vector è solitamente una struttura migliore di 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 
    } 
) 

è possibile refactoring per essere un po 'più bello estraendo la funzione che trova gli indici in una sola riga:

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

E poi scrivere

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

Se non stai bene con filtri e cerniere, si può attaccare con la for-di comprensione ma l'uso in un modo più funzionale:

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

yield costruisce una nuova collezione dai risultati della comprensione per-, quindi questa espressione restituisce alla raccolta si desidera tornare . seq.indices è un metodo equivalente a 0 until seq.size. Le parentesi graffe consentono di estendersi su più righe senza punto e virgola, ma è possibile farlo in-line, se si desidera:

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

probabilmente dovrei menzionare anche che normalmente se si sta scorrendo una matrice che non sarà necessario per riferirsi agli indici a tutti. Faresti fare qualcosa di simile

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

ma il vostro caso d'uso è un po 'insolito, in quanto richiede gli indici degli elementi, che non si dovrebbe normalmente essere interessati di (usando gli indici degli array è essenzialmente un rapido e dirty hack per accoppiare un elemento dati con un numero). Se si desidera acquisire e utilizzare la nozione di posizione, è preferibile utilizzare Map[Int, Boolean] o case class con tale campo.