Related
Suppose I have an array of
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
And I want to split it in 3, with two arrays containing the first and last X elements of the original array, and the third array containing the remaining elements, like so:
#1 - [0, 1, 2]
#2 - [3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
#3 - [13, 14, 15]
Is there a shorter/better way of doing that instead of:
const splitBy = 3;
const originalArray = Array.from(Array(16).keys());
const result = [
originalArray.slice(0, splitBy),
originalArray.slice(splitBy, -splitBy),
originalArray.slice(-splitBy),
];
console.log(result)
"better" is subjective... however, if you need this more than once, a generic function could be an option:
function multiSlice(a, ...slices) {
let res = [], i = 0
for (let s of slices) {
res.push(a.slice(i, s))
i = s
}
res.push(a.slice(i))
return res
}
// for example,
const originalArray = Array.from(Array(16).keys());
console.log(multiSlice(originalArray, 3, -3))
console.log(multiSlice(originalArray, 2, 5, 10, 12))
convert 9x9 array into 9 (3x3) array in javascript?
i have written the code, but its not pushing the 3x3's into separate array.
i want 9 3x3 arrays
let array =
[
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[2, 3, 1, 5, 6, 4, 8, 9, 7],
[3, 1, 2, 6, 4, 5, 9, 7, 8],
[4, 5, 6, 7, 8, 9, 1, 2, 3],
[5, 6, 4, 8, 9, 7, 2, 3, 1],
[6, 4, 5, 9, 7, 8, 3, 1, 2],
[7, 8, 9, 1, 2, 3, 4, 5, 6],
[8, 9, 7, 2, 3, 1, 5, 6, 4],
[9, 7, 8, 3, 1, 2, 6, 4, 5]
];
let final=[];
let row = [0,1,2];
let col = [0,1,2];
let counter = 0;
for ( let i = 0 ; i <= array.length - 1 ; i += 3 )
{
for(let j = 0 ; j <= array.length - 1 ; j += 3 )
{
final.push([]);
row.forEach( ele1 => {
final[counter].push([])
col.forEach( ele2 => {
final[counter][ele1].push(array[ele1+i][ele2+j]);
})
})
counter+=1;
}
}
console.log(final)
You can loop through the array using map function and check for the index values to break into arrays as required.
let myArr =[[1, 2, 3, 4, 5, 6, 7, 8, 9],
[2, 3, 1, 5, 6, 4, 8, 9, 7],
[3, 1, 2, 6, 4, 5, 9, 7, 8],
[4, 5, 6, 7, 8, 9, 1, 2, 3],
[5, 6, 4, 8, 9, 7, 2, 3, 1],
[6, 4, 5, 9, 7, 8, 3, 1, 2],
[7, 8, 9, 1, 2, 3, 4, 5, 6],
[8, 9, 7, 2, 3, 1, 5, 6, 4],
[9, 7, 8, 3, 1, 2, 6, 4, 5]];
let newArr = convertTo3x3(myArr);
console.log(newArr);
function convertTo3x3(myArr){
let array3x3 = [];
myArr.map((row, rIndex) => {
let tempArr = [];
let row3 = [];
row.map((item, lIndex) => {
// convert each row to 3x3 rows
if(lIndex % 3 == 0){
// reset row3 for new 3x3 arr on every 1st item of 3x3
row3 = [];
}
row3.push(item);
if(lIndex % 3 == 2){
// push 3x3 row to tempArr on every 3rd item of 3x3
tempArr.push(row3);
}
});
array3x3.push(tempArr);
});
return array3x3;
}
Your code seems to work fine, but if you want a more javascriptey code, that performs worse, here you go.
let array = [
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[2, 3, 1, 5, 6, 4, 8, 9, 7],
[3, 1, 2, 6, 4, 5, 9, 7, 8],
[4, 5, 6, 7, 8, 9, 1, 2, 3],
[5, 6, 4, 8, 9, 7, 2, 3, 1],
[6, 4, 5, 9, 7, 8, 3, 1, 2],
[7, 8, 9, 1, 2, 3, 4, 5, 6],
[8, 9, 7, 2, 3, 1, 5, 6, 4],
[9, 7, 8, 3, 1, 2, 6, 4, 5],
];
let final = [];
array
.reduce((a, c) => {
const chunk = (arr, n) =>
arr.length ? [arr.slice(0, n), ...chunk(arr.slice(n), n)] : [];
return [...a, ...chunk(c, 3)];
}, [])
.map((el, i) => {
if (i % 3 == 0) {
final = [...final, [el]];
} else {
final[Math.floor(i / 3)] = [...final[Math.floor(i / 3)], el];
}
});
console.log(final);
Your code is trying to do too much. Make it difficult to understand.
I would first break it up. Write a simple function than knows how to take an array-of-arrays and return an arbitrary rectangular selection from it. Something like this, that's easy to test:
/**
* Snip a rectangular section of an array of arrays (ragged, 2D array).
* The returned array-of-arrys will ALWAYS be the specified size, padded
* with 'undefined' values to the specified size.
*
* #param {Object[][]} arr - An array of arrays (ragged 2D array)
* #param {number} row - Origin row: {row,col} denotes the upper-left corner of the rectangle to snip
* #param {number} col - Origin column: {row,col} denotes the upper-left corner of the rectangle to snip
* #param {number} nrows - Number of rows to snip
* #param {number} ncols - Nunber of columns to snip
*
* #returns {Object[][]}
*/
function snip(arr, row, col, nrows, ncols ) {
const selection = [];
for ( let r = row, i = 0 ; r < row+nrows ; ++r, ++i ) {
selection[i] = [];
const tmp = arr[r] ?? [];
for ( let c = col, j = 0 ; c < col+ncols ; ++c, ++j ) {
selection[i][j] = tmp[c];
}
}
return selection;
}
Once you have that, then chopping up your larger array-of-arrays into 3x3 arrays is easy.
This code starts at the top left corner or your 9x9 array and returns a flat list containing 9 separate 3x3 arrays, chopped out left-to-right and top-to-bottom:
final = [];
for ( let x = 0 ; x < 9; x += 3 ) {
for ( let y = 0 ; y < 9 ; y += 3 ) {
// (x,y) denotes the top left corner of the desired sub-array
final.push( snip(arr, x,y, 3,3 ) );
}
}
The nice thing about this approach is that it is easy to test, and
.
.
.
It's flexible. It can handle a source array of any size, and you can chop it up into subarrays of any size and in any order, whatever you see fit to do.
Before marking this as answered by another question please note this is an array of arrays, not a flat array, also, the number I have given are an example, I have just shown them so you can visually see what is happening.
I am trying to loop through an array of arrays.
I have the following array:-
[
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[3, 2, 1, 6, 5, 4, 9, 8, 7],
[6, 5, 4, 9, 8, 7, 3, 2, 1],
[7, 8, 9, 3, 2, 1, 6, 5, 4]
]
How is it possible to transform this array into chunks of 3x3 for example:-
[
[1, 2, 3, 1, 2, 3, 1, 2, 3],
[4, 5, 6, 4, 5, 6, 4, 5, 6],
[7, 8, 9, 7, 8, 9, 7, 8, 9],
[3, 2, 1, 6, 5, 4, 9, 8, 7],
[6, 5, 4, 9, 8, 7, 3, 2, 1],
[7, 8, 9, 3, 2, 1, 6, 5, 4],
]
As you can see from the array above I have chunked it using the first 3 values from each array and then by the 2nd 3n from each array and lastly the final 3n from each array.
So the array would be chunked like the following:-
1 2 3 | 4 5 6 | 7 8 9
1 2 3 | 4 5 6 | 7 8 9
1 2 3 | 4 5 6 | 7 8 9
---------------------
3 2 1 | 6 5 4 | 9 8 7
6 5 4 | 9 8 7 | 3 2 1
7 8 9 | 3 2 1 | 6 5 4
I have tried to loop through each line and resetting the column count when it hits an increment and increasing the row but this didn't work.
I can update the question with previous attempts if this is of any help?
Also just a note, the array will be different sizes but always divisible by a particular number, for the above example I have chosen the number 3.
I have updated the question with more information.
The array of arrays will always be divisible by a specific number, this example shows a divisible number of 3.
This can be solved with a chunk as per this question Split array into chunks combined with a zip as per this Javascript equivalent of Python's zip function
This has the benefit of being able to reverse the operation to get back to the original.
/** #see: https://stackoverflow.com/questions/8495687/split-array-into-chunks */
function chunk(array, chunk) {
let result = [];
for (let i = 0; i < array.length; i += chunk) {
result.push(array.slice(i, i + chunk));
}
return result;
}
/** #see: https://stackoverflow.com/questions/4856717/javascript-equivalent-of-pythons-zip-function */
function zip(...rows) {
return [...rows[0]].map((_, c) => rows.map((row) => row[c]));
}
const array = [
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[3, 2, 1, 6, 5, 4, 9, 8, 7],
[6, 5, 4, 9, 8, 7, 3, 2, 1],
[7, 8, 9, 3, 2, 1, 6, 5, 4],
];
const result = chunk(array, 3)
.flatMap((innerChunk) =>
zip(...innerChunk.map((arr) => chunk(arr, 3)))
.map((arr) => arr.flat())
);
console.log(result.map((a) => a.join(', ')));
// Allows the result to be reverted to the original
const reversed = chunk(result, 3)
.flatMap((innerChunk) =>
zip(...innerChunk.map((arr) => chunk(arr, 3)))
.map((arr) => arr.flat())
);
console.log(reversed.map((a) => a.join(', ')));
You can do it with a nested loop, slicing the array each time based on the size of the outer array.
const arr = [
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9]
];
let out = [];
for(let i in arr) { out.push([]);}
arr.forEach((e, i) => {
let scale = e.length / arr.length;
for(let j in arr)
{
out[j] = out[j].concat(e.slice(j * scale, j * scale + scale));
}
});
console.log(out);
Here it is once more with your original array prior to your edit:
const arr = [
[1, 3, 2, 5, 2, 4, 3, 6, 8],
[1, 4, 3, 6, 7, 3, 6, 4, 5],
[2, 4, 1, 4, 6, 3, 7, 9, 7]
];
let out = [];
for(let i in arr) { out.push([]);}
arr.forEach((e, i) => {
let scale = e.length / arr.length;
for(let j in arr)
{
out[j] = out[j].concat(e.slice(j * scale, j * scale + scale));
}
});
console.log(out);
what's up? I hope you going well.
So, my question is, I have a array with number that I have to compare with another arrays (like 1 to X), what is the best way to:
1º compare the arrays and retrieve the numbers that are equals.
2º the numbers of elements that are equal (without using .length on the array with numbers are equals).
Example:
Array 1 = [1, 3, 4, 5, 6, 7, 8, 9, 11, 13, 16]
Array 2 = [1, 2, 3, 7, 9, 12, 16, 17]
That way, the total numbers is 5
And the numbers are: [1, 3, 7, 9, 16]
My method is using forEach and compare each item and using .length on the array with the numbers that are equals, there's another way or best way to do this?
Another example using more arrays:
Arr1 = [1, 2, 3, 5, 6, 7, 8, 10, 15]
Arr2 = [
[1, 3, 5, 7, 8, 9, 10, 11, 12],
[2, 5, 6, 7, 9, 10],
[1, 3, 5, 7, 10, 11, 13, 14, 15]
]
// Output
6, [1, 3, 5, 7, 8, 10]
5, [2, 5, 6, 7, 10]
7, [1, 3, 5, 6, 7, 10, 15]
Thanks for the answer.
I like using Set for this purpose. You can create a Set from your first array and then any lookup in that Set (using Set.has) is O(1) efficiency.
const arr1 = [1, 3, 4, 5, 6, 7, 8, 9, 11, 13, 16];
const arr2 = [1, 2, 3, 7, 9, 12, 16, 17];
const arr1Items = new Set(arr1);
const matched = arr2.filter(el => arr1Items.has(el));
console.log(matched.length, matched);
Arr2 is an array, not an object, your code would change accordingly
Arr1 = [1, 2, 3, 5, 6, 7, 8, 10, 15]
Arr2 = [
[1, 3, 5, 7, 8, 9, 10, 11, 12,],
[2, 5, 6, 7, 9, 10],
[1, 3, 5, 7, 10, 11, 13, 14, 15,]
]
Given that, the solution is a oneliner:
res = Arr2.map(a=>a.filter(x=>Arr1.indexOf(x)!=-1).length)
It should be straightforward but, just in case:
The [].indexOf(el) method give you the position of the parameter in the array, if that element is not present it will return -1. Therefore, the function
x => Arr1.indexOf(x)!=-1
returns true or false if x is present or not in the Arr1 array
The [].filter(fn) method use the fn function to evaluate every array element and give as result an array with the evaluated true elements.
a.filter(x => Arr1.indexOf(x)!=-1)
Means give me all the elements of array a presents in Arr1
Now we just have to count the lenght of that array
a.filter(x => Arr1.indexOf(x)!=-1).length
and pass this count to the [].map(fn) method to have the result we need.
The function I wrote below will give the results you want, but remember the function returns an array of arrays, even if the second parameter had only one array or was an array of elements instead of array of arrays (Works for both).
Arr1 = [1, 2, 3, 5, 6, 7, 8, 10, 15]
Arr2 = [
[1, 3, 5, 7, 8, 9, 10, 11, 12],
[2, 5, 6, 7, 9, 10],
[1, 3, 5, 7, 10, 11, 13, 14, 15]
]
Arr3 = [1, 5, 6, 9, 12, 15, 17]
function check(base_array,search_values)
{
if(base_array.length===0 || search_values.length===0)
{
return [];
}
else if(Array.isArray(search_values[0]))// Check if second parameter is an array of arrays.
{
var result=[];
search_values.forEach(search=>{
var result_sub=[];
search.forEach(key=>{
if(base_array.includes(key))
{
result_sub.push(key);
}
});
result.push(result_sub);
});
return result;
}
else
{
var result=[];
search_values.forEach(key=>{
if(base_array.includes(key))
{
result.push(key);
}
});
return [result];
}
}
console.log("Array of Arrays");
console.log(check(Arr1,Arr2));
console.log("Array of Elements");
console.log(check(Arr1,Arr3));
From the returned result you can loop through the value to get the elements and the number of elements by checking length of array.
result.forEach(element=>{
console.log(result.length, result);// number of elements doesn't have to be passed
});
What the Function does is it checks if any array is empty , then returns empty array [], if the second array is an array of arrays it loops through each array and then to each element in the sub array and checks if it exists in the first array, else if the array was array of elements, then it just loops through the elements and checks if it exists in the first array. And returns the result stored
I have an array, which contains duplicate values. How can I push duplicates in to another array?
let arr1 = [1, 5, 3, 6, 9, 5, 1, 4, 2, 7, 9], and duplicates array should be dupArr = [1, 5, 9]
You could filter the array by storing the previous checked values in a Set, which is here a closure.
var array = [1, 5, 3, 6, 9, 5, 1, 4, 2, 7, 9],
duplicates = array.filter((s => v => s.has(v) || !s.add(v))(new Set));
console.log(duplicates);