6

I have a 2d array of type boolean (not important) It is easy to iterate over the array in non-functional style. How to do it FP style?

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

for ex, I would like to iterate through all the rows for a given column and return a list of int that would match a specific function. Example: for column 3, iterate through rows 1 to 5 to return 4, 5 if the cell at (4, 3), (5, 3) match a specif function. Thx v much

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
  }

3 Answers 3

4

What about

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

where predicate is your function?

Note that initialized with (5,5) indexes goes from 0 to 4.

Update: based on your example

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
}

You may move the print in the fiter if you want too, and reverse the list if you want it exactly as in your example

Sign up to request clarification or add additional context in comments.

4 Comments

I think your sol would return an array if the initial structure is a 2d array?
Ah, another difference is I was thinking about filtering directly on the 2d array, but by doing so, I am loosing the row index: val children = matrix.filter(row => row(nodeIndex)) which returns 2 1d arrays - but I do not know which one
Not really, the structure I do fitering on is a Range, not an Array (as it was the indexes you wanted in the output). The result type is an IndexedSeq[Int], and it happens to be a Vector. Just do .toList if you want a List, but Vector is usually a better structure than List.
This is the non-FP version of what I'd like to achieve (edit main)
2

If you're not comfortable with filters and zips, you can stick with the for-comprehension but use it in a more functional way:

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

yield builds a new collection from the results of the for-comprehension, so this expression evaluates to the collection you want to return. seq.indices is a method equivalent to 0 until seq.size. The curly braces allow you to span multiple lines without semicolons, but you can make it in-line if you want:

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

Should probably also mention that normally if you're iterating through an Array you won't need to refer to the indices at all. You'd do something like

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

but your use-case is a bit unusual in that it requires the indices of the elements, which you shouldn't normally be concerned with (using array indices is essentially a quick and dirty hack to pair a data element with a number). If you want to capture and use the notion of position you might be better off using a Map[Int, Boolean] or a case class with such a field.

Comments

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

You can refactor it to be a bit more nicer by extracting the function that finds the indices in a single row only:

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

And then write

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.