# Testing equality of vectors in a 2 dimensional array

Hello together,
I have a problem testing equality of one line of a 2D array against a possible new line.

My goal is to add a new line only if a line with the same elements does not yet exist.
To achieve this I wrote the following code:

``````class Evaluation {
constructor() {
this.lines = [];

}

for (let newLine of cell.neighbors) {
// Suchen, ob es diese Zeile schon gibt
let pushIt = true;
for (let i = 0; i < this.lines.length; i++) {
let lineExists = 0;
for (let j = 0; j < newLine.length; j++) {
if (this.lines[i].includes(newLine[j])) {
//passenden Merker setzen
lineExists += 1;
}
}
if (lineExists == newLine.length) {
pushIt = false;
}
}
if (pushIt) {
this.lines.push(newLine);
}
}
}
}
``````

cell is an object that contains a 2D array neighbors. Each element cell.neighbors[i] is an array of 4 p5.Vectors. I have 64 instances of cell objects, Evaluation.addLines is called for each of them.
The cells live in a 444 grid.
Evaluation.lines should become a list of all straight lines covering 4 cells, each line should be present once.
After calling addLines for all 64 cells Evaluation.lines is a list of all straight lines covering 4 cells, each line is present 4 times.

I do not care for the order of elements in each line and I can not ensure that the order is equal in 2 representations of any given line.
That is why I thought it would be a good idea to loop over all existing lines (for(let i…) with a nested inner loop (for(let j…) where I count how many of the vectors in newLine are present in that particular existing line.
If all Vectors are present (lineExists == newLine.length) I set the pushIt-flag false to not push that line into the lines-array.

While debugging I saw that sometimes pushIt is set to false, but after adding the neighbors of all 64 cells I still get 304 lines instead of the 76 lines I expect.

Can anybody tell me where my error lies and point me in the right direction please?

Best regards from Germany

PS: I edited the title to include “of vectors”

Basically we shouldn’t use method Array::includes() to compare objects.

B/c object comparison in JS doesn’t check their contents (properties & their values).

``````'use strict';

function setup() {
noCanvas();

const vec = createVector(), arr = [ vec ];

print(arr.includes(vec)); // true
print(arr.includes(createVector())); // false

print(arr == vec, arr == createVector()) // true, false

print(createVector() == createVector()); // false
print(createVector().x == createVector().x); // true
}
``````

That actually makes the algorithm slightly more complex.

Just coded a double function which relies on method Array::some() for a customized object comparison:

The idea is to clone the 2nd vector array row and then invoke Array::some() inside the 1st vector array row’s loop.

Inside Array::some()'s callback we use method p5.Vector.equals() to check whether the contents of both vectors match.

Every time both vectors match we Array::splice() that vector outta the cloned 2nd vector array row:

Otherwise, if Array::some() fails to find a match, we `break` from the loop.

That function returns `true` only if the cloned 2nd vector array row becomes empty:

``````'use strict';

function setup() {
noCanvas();

const
row = [
createVector(PI, TAU),
createVector(),
createVector(PI, TAU)
],

equal = [
createVector(PI, TAU),
createVector(PI, TAU),
createVector()
],

diff = [
createVector(PI, TAU),
createVector(TAU, PI),
createVector()
],

same = [
createVector(PI, TAU),
createVector(PI, TAU),
createVector(PI, TAU),
createVector(PI, TAU)
];

print(rowsContainSameVecs(row, equal));  // true
print(rowsContainSameVecs(row, diff));   // false

print(rowsContainSameVecs(row, row));    // true
print(rowsContainSameVecs(equal, row));  // true
print(rowsContainSameVecs(equal, diff)); // false

print(rowsContainSameVecs(row, same));   // false
print(rowsContainSameVecs(same, row));   // false
}

function rowsContainSameVecs(vecRowOne, vecRowTwo) {
if (vecRowOne?.length != vecRowTwo?.length)  return false;

vecRowTwo = vecRowTwo.slice();

for (const vecOne of vecRowOne)
if (!vecRowTwo.some(removeIfSameVec, vecOne))  break;

return !vecRowTwo.length;
}

function removeIfSameVec(vec, idx, arr) {
const same = vec.equals(this);
same && arr.splice(idx, 1);
return same;
}
``````
2 Likes

Thank you for your input and the coding you provided.
I will implement and test it in my program and report back.

Here I am again…

I ended up not quite using the algorithm you provided. I may do so in the future and it may well be better than my algorithm, but…

• I´m a beginner in js
• I´m not (yet) comfortable with the idea and use of callback functions
• I don´t fully understand the benefit of your algorithm compared to mine.

What did I do?

``````  addLines(cell) {
for (let newLine of cell.neighbors) {
// Suchen, ob es diese Zeile schon gibt
let pushIt = true;
for (let i = 0; i < this.lines.length; i++) {
let lineExists = 0;
for (let j = 0; j < newLine.length; j++) {

//          if (this.lines[i].includes(newLine[j])) {
//            //passenden Merker setzen
//            lineExists += 1;
//          }
for (let k = 0; k < this.lines[i].length; k++) {
if (this.lines[i][k].equals(newLine[j])) {
//count number of identical vectors per line
lineExists += 1;
}
}

}
// if all vectors are identical
if (lineExists == newLine.length) {
pushIt = false;
break;
}
}
if (pushIt) {
this.lines.push(newLine);
}
}
}
``````

I added a 4th layer of nested loops to go throug the elements of the existing line(s) and the new line to compare them.
I used p5.Vector.equals() instead of == to compare the vectors. This is the core point I took from your suggestion and I´m sure it was my main mistake.

As far as I understand it the explicit check for same length in your function rowsContainSameVecs() is an improvement over my algorithm.
I think that one is minor in my special case, as I ensure lines of length 4 at creation of my inputs.

One point I don´t really understand is:
what does the “this” point to in the line

``````  const same = vec.equals(this);
```?``````

That keyword `this` inside the callback removeIfSameVec(vec, idx, arr) refers to the 2nd parameter from method Array::some(callbackFn, thisArg):

So it’s comparing each p5.Vector object from vecRowTwo[] cloned array to the current p5.Vector object (represented by loop’s iterator vecOne) from vecRowOne[] array.

If they’re equals(), I use Array::splice(startIndex, deleteCount) method to delete the current index from vecRowTwo[] cloned array (represented by callback’s parameter arr) to make sure that p5.Vector isn’t found again for the rest of the loop:

At the end of the loop it’s expected for vecRowTwo[] cloned array to be empty (its length = 0):

If so, it means that each p5.Vector object from vecRowOne[] array has found an equals() among vecRowTwo[] cloned array.

1 Like

Thank you again for the additional explanations.

At the moment my problem is solved.
I will make a note to try out your suggested algorithm to see if it makes an improvement over the solution I chose for now.

I have a lot more to learn about javascript and your explanations helped me a lot to that end.

1 Like