2011-09-12 9 views
5

Mam tablicę 2d typu boolean (nie ważne) Łatwo jest iterować po tablicy w niefunkcjonalnym stylu. Jak to zrobić w stylu FP?2d iteracja szeregowa scala

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

dla ex, Chciałbym iterację wszystkich wierszy dla danej kolumnie i zwraca listę int, które odpowiadają określonej funkcji. Przykład: dla kolumny 3 wykonaj iterację w wierszach od 1 do 5, aby powrócić do 4, 5, jeśli komórka w punkcie (4, 3), (5, 3) jest zgodna z funkcją specif. Thx v znacznie

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 
    } 

Odpowiedz

4

Co

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

gdzie predicate to funkcja?

Zauważ, że zainicjowana (5,5) indeksów idzie od 0 do 4.

Aktualizacji: oparta na przykład

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 
} 

można przesunąć drukiem w fiter jeśli chcesz również i do tyłu na liście, jeśli chcesz go dokładnie tak, jak w przykładzie

+0

Myślę, że twój zol zwróciłby tablicę, gdyby początkowa struktura była tablicą 2d? – jts

+0

Ah, inną różnicą jest to, że myślałem o filtrowaniu bezpośrednio na tablicy 2d, ale przez to tracę indeks wiersza: val children = matrix.filter (row => row (nodeIndex)), który zwraca 2 tablice 1d - ale nie wiem, który z nich – jts

+0

Niezupełnie, struktura, którą robię fitering jest Range, a nie Array (jak to było indeksy, których chciałeś w wydajność). Typ wyniku to IndexedSeq [Int], a tak się składa, że ​​jest to Vector. Po prostu wykonaj polecenie .toList, jeśli chcesz mieć listę, ale wektor jest zazwyczaj lepszą strukturą niż lista. –

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

można byłaby to być nieco bardziej ładniejszy przez ekstrakcję funkcja, która stwierdzi, indeksy tylko w jednym rzędzie:

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

a następnie napisać

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

Jeśli nie jesteś wygodne z filtrami i suwakami, można trzymać się za-rozumienia, ale użytku to w sposób bardziej funkcjonalny:

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

yield buduje nową kolekcję z wynikami do-zrozumienia, więc to wyrażenie do kolekcji chcesz powrócić . seq.indices to metoda równoważna z 0 until seq.size. Nawiasy klamrowe pozwala na zajmującą wiele wierszy bez średnikami, ale można zrobić to w jednej linii, jeśli chcesz:

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

prawdopodobnie powinien również wspomnieć, że normalnie jeśli iteracja tablicy nie trzeba będzie w ogóle odnosić się do wskaźników. Można by zrobić coś takiego

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

ale twój use-case jest nieco nietypowe, że wymaga to indeksy pierwiastków, które nie powinny być normalnie zajmują się (za pomocą wskaźników tablicy jest przede wszystkim szybkie i brudny hack do parowania elementu danych z numerem). Jeśli chcesz uchwycić i wykorzystać pojęcie pozycji, możesz lepiej skorzystać z pola Map[Int, Boolean] lub case class.