How to compare multidimensional array by columns - javascript

I am creating a function to compare items in a multidimensional array of length 6. I compare from bottom to top and left to right. If the first elements (index 0) are as follows i[0][5] > i[0][4] > i[0][3] > i[0][2] > i[0][1] > i[0][0] it returns false and if there is only at least one element that does not respect the rule above it should return false.
When I try to use for loop, the program only returns 1 result not all expected ones.
let multidimArr = [
[1, 2, 3, 2, 1, 1]
[2, 4, 4, 3, 2, 2]
[5, 5, 5, 5, 4, 4]
[6, 6, 7, 6, 5, 5]
[4, 7, 6, 8, 7, 6]
[4, 9, 6, 7, 8, 9]
];
function compare() {
for (var i=0, len=multidimArr.length; i<len; i++) {
for (var j=0, len2=multidimArr[i].length; j<len2; j++) {
if( i <= 0 ) continue;
if ( multidimArr[i][j] < multidimArr[i - 1][j] ) {
return false
);
} else if( multidimArr[i][j] > multidimArr[i - 1][j] ){
return true;
}
}
console.log('the status is [' + compare() + ']');
For this code the expected result is false for the first column, true for the second, false for the 3rd, true for 4th, false for 5th and true for last column.
Unfortunately it only return false.

You could reduce the array and take true for the first row and then check the last and actual value and respect the last check.
function check(array) {
return array.reduce((r, a, i, { [i - 1]: b }) => a.map((v, j) => i
? r[j] && b[j] < v
: true
), []);
}
var array = [[1, 2, 3, 2, 1, 1], [2, 4, 4, 3, 2, 2], [5, 5, 5, 5, 4, 4], [6, 6, 7, 6, 5, 5], [4, 7, 6, 8, 7, 6], [4, 9, 6, 7, 8, 9]];
console.log(check(array));

Related

Split array into equal chunks, exclude the last chunk that is smaller and redistribute its items equally between the previous chunks

I have an array of items :
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
// or more items
I have managed to split it into chunks by 3 items per array and pushed them into an array of arrays :
[
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
[10, 11] // <== the last one has less items than the others
]
I want to redistribute the items of the last array equally between the previous chunks :
// expected output
[
[1, 2, 3, 10],
[4, 5, 6, 11],
[7, 8, 9],
]
or even more complex like redistrbuting the items at random positions :
// expected output
[
[1, 2, 3, 10],
[4, 5, 6],
[7, 8, 9, 11],
]
so far this is what i have reached :
let array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
let arrayOfChunks = [];
let amount = 3;
for (let i = 0; i < array.length; i += amount) {
const chunk = array.slice(i, i + amount);
if (chunk.length === amount) {
arrayOfChunks.push(chunk);
} else {
console.log(chunk);
// output [10,11]
}
}
return arrayOfChunks;
I tried making another loop dpending on the arrayOfChunks.length = 3 where I could redistribute the items of the last array evenly into the arrayOfChunks, but sometimes the arrayOfChunks.length = 5 which require another splitting and merging into the previous generated equal chunks.
thanks for your help :)
After chunking the array normally, pop off the last subarray if the chunk number didn't divide the original array length evenly. Then, until that last popped subarray is empty, push items to the other subarrays, rotating indicies as you go.
const evenChunk = (arr, chunkSize) => {
const chunked = [];
for (let i = 0; i < arr.length; i += chunkSize) {
chunked.push(arr.slice(i, i + chunkSize));
}
if (arr.length % chunkSize !== 0) {
const last = chunked.pop();
let i = 0;
while (last.length) {
chunked[i].push(last.shift());
i = (i + 1) % chunked.length;
}
}
console.log(chunked);
};
evenChunk([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17], 7);
evenChunk([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], 3);

Get 3x3 blocks from 9x9 2d array as String

I am learning Javascript and currently found myself with the following problem. I need to get each individual 3x3 block of a 9x9 2d array as a string, separated by commas.
What I mean is, for example, let's say I have the following array:
var 2dArray = [
[5, 3, 5, 6, 7, 8, 9, 1, 2],
[6, 7, 1, 1, 9, 5, 3, 4, 8],
[1, 9, 2, 3, 4, 2, 5, 6, 7],
[8, 5, 9, 7, 6, 1, 4, 2, 3],
[4, 2, 6, 5, 5, 3, 7, 9, 1],
[7, 1, 3, 1, 2, 4, 8, 5, 6],
[9, 6, 1, 5, 3, 7, 2, 8, 4],
[2, 8, 7, 5, 1, 9, 6, 3, 5],
[3, 4, 5, 6, 8, 6, 1, 7, 9] ]
The result should be something like 535671192,678195342, 912348657, ... and so on, until the string is made of all the 3x3 blocks.
I thought that making nested for loops would be the best approach, but got confused along the way and I would appreciate your help.
Thank you.
You can use two loops to iterate over the positions of all the possible top left corners and another two loops to get all the elements in that square.
var arr = [
[5, 3, 5, 6, 7, 8, 9, 1, 2],
[6, 7, 1, 1, 9, 5, 3, 4, 8],
[1, 9, 2, 3, 4, 2, 5, 6, 7],
[8, 5, 9, 7, 6, 1, 4, 2, 3],
[4, 2, 6, 5, 5, 3, 7, 9, 1],
[7, 1, 3, 1, 2, 4, 8, 5, 6],
[9, 6, 1, 5, 3, 7, 2, 8, 4],
[2, 8, 7, 5, 1, 9, 6, 3, 5],
[3, 4, 5, 6, 8, 6, 1, 7, 9]
];
let res = [];
for (let i = 0; i < 9; i += 3) {
for (let j = 0; j < 9; j += 3) {
let curr = "";
for (let k = 0; k < 3; k++) {
for (let l = 0; l < 3; l++) {
curr += arr[i + k][j + l];
}
}
res.push(curr);
}
}
console.log(res);
The issue can also be solved by loops but it's good practice to solve it using the Array.map() function.
let arrayRow = "";
const resultArray = Array2d.map((element, index) => {
return arrayRow + element.map((element, i) => {
return element.toString();
});
});
you should try like this too.
var arr = [
[5, 3, 5, 6, 7, 8, 9, 1, 2],
[6, 7, 1, 1, 9, 5, 3, 4, 8],
[1, 9, 2, 3, 4, 2, 5, 6, 7],
[8, 5, 9, 7, 6, 1, 4, 2, 3],
[4, 2, 6, 5, 5, 3, 7, 9, 1],
[7, 1, 3, 1, 2, 4, 8, 5, 6],
[9, 6, 1, 5, 3, 7, 2, 8, 4],
[2, 8, 7, 5, 1, 9, 6, 3, 5],
[3, 4, 5, 6, 8, 6, 1, 7, 9]
];
let res = [];
let i = 0,j = 0;
let justOneStr = "";
while(i < 9 && j < 9){
justOneStr += arr[i][j];
if(i % 3 == 2 && j % 3 == 2){
res.push(justOneStr);
justOneStr="";
}
if((j % 9 == 8 || j % 3 == 2) && i % 3 != 2){
j -= 3;
i += 1;
}
else if(j % 9 == 8 && i % 3 == 2){
j -= 9;
i += 1;
}
else if(i % 3 == 2 && j % 3 == 2){
i -= 2;
}
j++;
}
console.log(res);
Here's a fairly straightforward nested reduce() that returns an array of matrices of the specified size. It touches each element once, and uses the coordinates in the passed matrix to determine which sub-matrix and sub-matrix row to accumulate into.
const
matrix = [
[5, 3, 5, 6, 7, 8, 9, 1, 2],
[6, 7, 1, 1, 9, 5, 3, 4, 8],
[1, 9, 2, 3, 4, 2, 5, 6, 7],
[8, 5, 9, 7, 6, 1, 4, 2, 3],
[4, 2, 6, 5, 5, 3, 7, 9, 1],
[7, 1, 3, 1, 2, 4, 8, 5, 6],
[9, 6, 1, 5, 3, 7, 2, 8, 4],
[2, 8, 7, 5, 1, 9, 6, 3, 5],
[3, 4, 5, 6, 8, 6, 1, 7, 9]],
subdivide = (matrix, width, height) => {
return matrix.reduce((acc, row, i) => {
row.reduce((_acc, x, j, row) => {
const grid = Math.floor(j / width) + Math.floor(i / height) * (Math.ceil(row.length / width));
const gridRow = i % height;
_acc[grid] ??= [];
(_acc[grid][gridRow] ??= []).push(x);
return _acc;
}, acc)
return acc;
}, [])
},
subdividedmatrix = subdivide(matrix, 3, 3);
// log submatrices
subdividedmatrix.forEach(m => console.log(JSON.stringify(m)));
// map to strings
console.log(subdividedmatrix.map(submatrix => submatrix.flat().join('')))
.as-console-wrapper { max-height: 100% !important; top: 0; }

Javascript: Manipulate array to return shortest node

I have an array as below
var a = [ [ 5, 5, 1, -4 ], [ 3, 7, 3, -1 ], [ 7, 3, 4, 1 ], [ 5, 5, 5, 0 ] ]
Every nested array index:2 element indicates its distance from 0(Zero) and every index:3 element indicate how near it is to its next poll point.
I am trying to sort this array so I can get nested array which is near to index:0 with reference to index:2 element and its next poll point is very near.
For example, my answer here is [ 3, 7, 3, -1 ] because
though [ 5, 5, 1, -4 ] , index:2 is very near to 0 its next point is located at after/before 4 positions. But for [ 3, 7, 3, -1 ] next poll point is at one position.
I tried with sorting like below
js
inDiff = inDiff.sort( function(a,b ){
if ( a[2] < b[2]) {
if ( Math.abs(a[3]) < Math.abs(b(3)) ){
return Math.abs(b[3]) - Math.abs(a[3]);
}
}
});
Update 1
As asked in the comment I am adding explanation to each element of the nested array. For example in nested array [ 5, 5, 1, -4 ]
Index:0: Value 5 Represents 1st Number that I am looking for
Index:1 Value 5 Represents 2nd Number ( next poll point number)
By Adding these two numbers I will achieve my requirement of finding two numbers which can sum up for 10.
Index 2 : Value 1 : Indicates index of 1st number nothing but 5 in the source array
Index 3 : Value -4 : Indicates difference between indexes of Index:0 and Index:1 number of nested array from source array.
But nothing happens with my array.
Any help, much appreciated.
Assuming the input always follows requirements this demo uses .reduce()
const AA = [
[5, 5, 1, -4],
[3, 7, 3, -1],
[7, 3, 4, 1],
[5, 5, 5, 0]
];
let result = AA.reduce((min, now, idx, AoA) => {
let distTo0 = array => Math.abs(Math.floor(array[2]) + Math.floor(array[3]));
min = distTo0(now) < distTo0(min) ? now : min;
return min;
});
console.log(result);
The following demo includes all of the rules as I understood them:
const crazyLogic = arrayOfArrays => {
let AAClone = JSON.parse(JSON.stringify(arrayOfArrays));
const shared = AAClone[0][0] + AAClone[0][1];
const rules = [`Must be an array of number arrays`, `The sum of index 0 and 1 of each sub-array must be identical`, `Mismatched sub-array lengths`];
let message = !AAClone.every(sub => Array.isArray(sub)) ? rules[0] : !AAClone.every(sub => sub.every(num => num + 0 === num)) ? rules[0] : !AAClone.every(sub => sub[0] + sub[1] === shared) ? rules[1] : !AAClone.every(sub => sub.length === 4) ? rules[2] : null;
if (message !== null) {
return message;
}
return AAClone.reduce((min, now, idx, AoA) => {
let distTo0 = array => Math.abs(Math.floor(array[2]) + Math.floor(array[3]));
min = distTo0(now) < distTo0(min) ? now : min;
return min;
});
};
/* Input rules:
1. Must be an array of arrays (only numbers)
2. Each sum of subArray[0] + subArray[1] must be identical
3. Each subArray.length = 4
*/
// AAa returns [ 3, 7, 3, -1 ]
const AAa = [
[5, 5, 1, -4],
[3, 7, 3, -1],
[7, 3, 4, 1],
[5, 5, 5, 0]
];
// AA1 breaks rule 1
const AA1 = [
[5, 5, 1, -4],
[3, 7, 3, -1],
[7, 3, ' X', 1],
[5, 5, 5, 0]
];
// AAO breaks rule 1
const AAO = [
[5, 5, 1, -4],
[3, 7, 3, -1],
[7, 3, 4, 1],
[5, 5, 5, 0], {}
];
// AA2 breaks rule 2
const AA2 = [
[5, 5, 1, -4],
[3, 17, 3, -1],
[7, 3, 4, 1],
[5, 5, 5, 0]
];
// AA3 breaks rule 3
const AA3 = [
[5, 5, 1, -4],
[3, 7, 3, -1],
[7, 3, 4, 1],
[5, 5, 5]
];
console.log(crazyLogic(AAa));
console.log(crazyLogic(AA1));
console.log(crazyLogic(AAO));
console.log(crazyLogic(AA2));
console.log(crazyLogic(AA3));

remove duplicate elements in proceeding arrays inside array of arrays

We have an array of arrays like this:
const arrays = [
[0, 1, 2, 3, 4, 4, 4, 4],
[5, 6, 7, 8, 9, 10, 11, 11],
[2, 7, 10, 12],
[0, 7, 10, 14]
];
There may be duplicate elements in each array and that's fine.
But I'm after a proper solution to remove duplicate elements in each set comparing to lower sets!
So as we have a 0 in the first array and the last array, we should consider the 0 in last one a duplication and remove it...
the desired result would be:
[0, 1, 2, 3, 4, 4, 4, 4],
[5, 6, 7, 8, 9, 10, 11, 11],
[12],
[14]
It's a confusing issue for me please help...
You could collect the values in an object with index as value, and filter for values who are at the same index.
const
arrays = [[0, 1, 2, 3, 4, 4, 4, 4], [5, 6, 7, 8, 9, 10, 11, 11], [2, 7, 10, 12], [0, 7, 10, 14]],
seen = {},
result = arrays.map((array, i) => array.filter(v => (seen[v] ??= i) === i));
result.forEach(a => console.log(...a));
const arrays = [
[0, 1, 2, 3, 4, 4, 4, 4],
[4, 4, 5, 6, 7, 8, 9, 10, 11, 11],
[2, 7, 10, 12],
[0, 7, 10, 14]
]
let filtered = arrays.map((row, i) => {
// concat all previous arrays
let prev = [].concat(...arrays.slice(0, i))
// filter out duplicates from prev arrays
return row.filter(r => !prev.includes(r))
})
console.log(filtered)
We can do this using Array#reduce and maintain a seen Set, which will have all visited numbers from each array.
Once you iterate over an array you push all visited elements in the seen Set, then push a new array filtered by the elements not in the seen Set:
const arrays = [
[0, 1, 2, 3, 4, 4, 4, 4],
[5, 6, 7, 8, 9, 10, 11, 11],
[2, 7, 10, 12],
[0, 7, 10, 14]
];
const removeDupsInSibling = (arr) => {
let seen = new Set();
return arr.reduce((acc, a)=> {
const f = a.filter(v => !seen.has(v));
seen = new Set([...seen, ...a]);
acc.push(f);
return acc;
}, []);
}
console.log(removeDupsInSibling(arrays));
There are plenty of inefficient ways to do this, but if you want to do this in O(n), then we can make the observation that what we want to know is "which array a number is in". If we know that, we can run our algorithm in O(n):
for every element e in array at index i:
if index(e) == i:
this is fine
if index(e) < i:
remove this e
So let's just do literally that: we allocate an object to act as our lookup, and then we run through all elements:
const lookup = {};
const arrays = [
[0, 1, 2, 3, 4, 4, 4, 4],
[5, 6, 7, 8, 9, 10, 11, 11],
[2, 7, 10, 12],
[0, 7, 10, 14]
];
const reduced = arrays.map((array, index) => {
// run through the elements in reverse, so that we can
// safely remove bad elements without affecting the loop:
for(let i=array.length-1; i>=0; i--) {
let value = array[i];
let knownIndex = (lookup[value] ??= index);
if (knownIndex < index) {
// removing from "somewhere" in the array
// uses the splice function:
array.splice(i,1);
}
}
return array;
});
console.log(reduced);
For an alternative, where the loop+splice is taken care of using filter, see Nina's answer.
Simple, clean and high performance solution:
const arrays = [
[0, 1, 2, 3, 4, 4, 4, 4],
[5, 6, 7, 8, 9, 10, 11, 11],
[2, 7, 10, 12],
[0, 7, 10, 14]
];
const duplicates = {};
const answer = arrays.map( (array, level) => {
return array.filter( el => {
if ( duplicates[el] < level ) {
// return nothing; fine
} else {
duplicates[el] = level;
return el
}
})
});
console.log(JSON.stringify(answer))
here is on-liner and less-readable form:
const d = {}, arrays = [ [0, 1, 2, 3, 4, 4, 4, 4], [5, 6, 7, 8, 9, 10, 11, 11], [2, 7, 10, 12], [0, 7, 10, 14]];
const answer = arrays.map((a,l)=> a.filter(el=> d[el]<l ? 0 : (d[el]=l,el)));
console.log(JSON.stringify(answer))
const arrays = [
[0, 1, 2, 3, 4, 4, 4, 4],
[5, 6, 7, 8, 9, 10, 11, 11],
[2, 7, 10, 12],
[0, 7, 10, 14],
];
const output = arrays.reduce(
({ output, set }, current, i) => {
output[i] = current.filter((num) => !set.has(num));
[...new Set(output[i])].forEach((num) => set.add(num));
return { output, set };
},
{ output: [], set: new Set() }
).output;
console.log(output);
Gets the exact output you want:
[
[
0, 1, 2, 3,
4, 4, 4, 4
],
[
5, 6, 7, 8,
9, 10, 11, 11
],
[ 12 ],
[ 14 ]
]

Splice Function in Javascript is adding 4 empty rows to my array?

I want to remove all the rows whose length is less than some value. I'am using Splice function in javascript to do this.
for (var i = 0; i < table.length; i++) {
if (table[i].length<=6) {
table.splice(i, 1);
}
}
but two rows with length:0 are being added at the beginning and at the end of my array this is the actual array
extra rows added after being spliced
whis is this happening?
how can i get rid of it?
I suggest to splice from the end to start, because if an element is spliced, the following elements are move a place in front of the array.
var table = [
[0, 1, 2, 3, 4, 5],
[],
[0],
[],
[],
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13],
[0, 1, 2, 3, 4, 5, 6, 7],
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[0, 1, 2, 3, 4, 5, 6, 7, 8],
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[0],
[0],
[],
[],
[1]
],
i = table.length;
while (i--) {
if (table[i].length <= 6) {
table.splice(i, 1);
}
}
console.log(table);
Try with this:
for (var i = 0; i < table.length; i++) {
if (table[i].length<=6) {
table.splice(i, 1);
i--;
}
}
After deleting a row you have to decrease the index to the array because the elements of the array have been shifted by the precious removal.

Categories

Resources