The easiest way to create vector of pairs

Hello,
I try to figure out the easiest way in Scala to create an array of arrays, which are pairs (Actually any pairs is a Vector because later I will modify the pairs set to contain more than 2 elements). My first question: Is there a way to do it functionality and not with indices?

My second question (even with indices…), I tried to do something like

var vect: Vector[Vector[Int]] (initizlized to be empty)

psudo code:
for i=0…length
for j=0…length && j!=i
vect[i][j]=(i,j)
What is the right way to do it in scala?
My problem was that I couldn’t do something like vect +: Vector(i,j) because this result should be assigned to a second vector (of pairs…). However, it seems weird for me to do something like:

var vect2 = vect ++ Vector(i,j) (I’m not sure it works in any case), becuase in this case vect really has no meaning, but what is the alternative to assign values to this object (or in english, is it possible to enter the elements to vect without define a dummy object?).
Thanks in advance!

Vector.tabulate(length, length)((i, j) => Vector(i, j))

2 Likes

Your pseudocode contains the condition j != i, but the way you use indices, it’s not clear, if they should simply be skipped or some placeholder be inserted, so that the later indices match.

@martijnhoekstra’s solution inserts Vector(i,j) always. If you require a placeholder when i == j, e.g. an empty vector, you can add that to the generating function:

Vector.tabulate(length, length)((i, j) =>
  if(i == j) Vector()
  else Vector(i, j)
)

If you want to skip these elements entirely, (which means the second index will no longer correspond to the second element of the pair for j > i), you can either modify the tabulate call:

Vector.tabulate(length, length - 1)((i, j) =>
  if(j < i) Vector(i, j)
  else Vector(i, j + 1)
)

or you can use for-comprehensions pretty similar to your pseudo code:

for {
  i <- 0 until length
} yield for {
  j <- 0 until length
  if j != i
} yield Vector(i,j)

This is still functional and returns the same result as the modified tabulate. In this case, I find the for comprehension easier to read.

If neither is what you need, could you write down the expected result for e.g. length of 3?

2 Likes

I haven’t had my coffee yet, but I’m really curious about using a nested for-comprehension in the yield block; would it be semantically the same to do this?

for {
  i <- 0 until length
  j <- 0 until length
  if j != i
} yield Vector(i, j)
1 Like

No, this would have a differnt result.

A single for-comprehension translates only the last arrow into a map, all earlier become a flatMap. This means, the result is always flattened.

With the single comprehension, you’ll get a two-dimensional vector (one from the comprehension, one from the Vector in the yield clause), while the nested one will result in a 3-dimensional vector.

E.g. for length = 3:

for {
    i <- 0 until length
    j <- 0 until length
    if j != i
  } yield Vector(i, j) 

res7: IndexedSeq[Vector[Int]] = Vector(
  Vector(0, 1), Vector(0, 2), Vector(1, 0), Vector(1, 2), Vector(2, 0), Vector(2, 1)
)

for {
    i <- 0 until length
  } yield for {
    j <- 0 until length
    if j != i
  } yield Vector(i, j) 

res8: IndexedSeq[IndexedSeq[Vector[Int]]] = Vector(
  Vector(Vector(0, 1), Vector(0, 2)),
  Vector(Vector(1, 0), Vector(1, 2)),
  Vector(Vector(2, 0), Vector(2, 1))
)
1 Like

Thank you for the detailed reply! This is very helpful.

Thanks for the full answer!
I actually needed exactly a variation of what you
suggested so I did gap the differences.