bcr
bcr

Reputation: 950

Scala Immutable Array Filter Condition

I am working with an adjacency matrix in a project and I need to remove an edge safely.

The project I am working on uses the matrix in the following way: Map[Agent, Array[Edge]]. I would like to use the Array.filter function to remove the edge in question. I am doing this to avoid using indexing or zipWithIndex.

After adding four "agent"s to the matrix and adding two undirected edges this is what my matrix looks like:

A1: null, 1.1, null, null, 
A2: 1.1, null, null, null, 
A3: null, null, null, 1.2, 
A4: null, null, 1.2, null, 

As you can see the edges are (A1, A2) and (A3, A4).

To remove edge (A1, A2) I am using this:

map = map.updated(a1, map(a2).filter(e => e != null && e.toAgent != a2))

However, this is removing the null entries (as expected). This is what my matrix looks like after removing an edge using the above technique:

A1: 1.1, 
A2: 
A3: null, null, null, 1.2, 
A4: null, null, 1.2, null, 

The role of null entries is important because it allows for me to quickly insert new edges in their correct location. I am looking for a solution to filtering out a single edge.

The problem with simply doing:

map = map.updated(a1, map(a2).filter(e => e.toAgent != a2))

Is that I am operating on null entries which causes a NullPointerException (obviously). I am looking for a solution to this.

To reiterate, I want to filter using an attribute of each edge that may or may not be null. Is there a way to implement a type of "skip if null"?

Thanks for your help and advice.

Upvotes: 0

Views: 207

Answers (2)

Tim
Tim

Reputation: 27421

You would be better off using Option rather than having null elements. Scala Option is a much more powerful and type-safe alternative to null.

A1: None,      Some(1.1), None,      None, 
A2: Some(1.1), None,      None,      None, 
A3: None,      None,      None,      Some(1.2), 
A4: None,      None,      Some(1.2), None,

You can filter an Option and it will only test Some values and skip None values.

map = map.updated(a1, map(a2).map(_.filter(_.toAgent == a2)))

Upvotes: 1

Aivean
Aivean

Reputation: 10882

I think you're missing the real problem.

The way how you deal with nulls is fine. The problem is that you're trying to use filter, which eliminates elements from your collection, shortening it.

If you want to replace certain elements in your collection with nulls, the immutable way to do it is by using map:

var arr = Array(null, 1.1, null, null)
arr = arr.map(e => if (e == 1.1) null else e)
println(arr.toList)  // List(null, null, null, null)

However, note a few things.

  1. Array in scala is mutable. Meaning, that you can do following:

    arr(edgeIndex) = null
    

    This will replace your edge with null.

  2. Scala has immutable sequence, Vector. If you use it instead of array, you can have immutability and indexed updates, like this:

    var vec = Vector(null, 1.1, null, null)
    vec = vec.updated(edgeIndex, null)
    println(vec) // Vector(null, null, null, null)
    

Upvotes: 0

Related Questions