Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I have multiple arrays in a main/parent array like this:
var arr = [
[1, 17],
[1, 17],
[1, 17],
[2, 12],
[5, 9],
[2, 12],
[6, 2],
[2, 12],
[2, 12]
];
I have the code to select the arrays that are repeated 3 or more times (> 3) and assign it to a variable.
The code is:
var arr = [[1, 17], [1, 17], [1, 17], [2, 12], [5, 9], [2, 12], [6, 2], [2, 12]]
arr.sort((a, b) => a[0] - b[0] || a[1] - b[1])
// define equal for array
const equal = (arr1, arr2) => arr1.every((n, j) => n === arr2[j])
let GROUP_SIZE = 3
first = 0, last = 1, res = []
while(last < arr.length){
if (equal(arr[first], arr[last])) last++
else {
if (last - first >= GROUP_SIZE) res.push(arr[first])
first = last
}
}
if (last - first >= GROUP_SIZE) res.push(arr[first])
console.log(res)
So the final result is:
console.log(repeatedArrays);
>>> [[1, 17], [2, 12]]
My problem: But the problem is, I have an array like this {from: [12, 0], to: [14, 30]}.
var arr = [
[1, 17],
[1, 17],
[1, 17],
[2, 12],
[5, 9],
[2, 12],
[6, 2],
{from: [12, 0], to: [14, 5]},
{from: [12, 0], to: [14, 5]},
{from: [4, 30], to: [8, 20]},
{from: [12, 0], to: [14, 5]},
{from: [4, 30], to: [8, 20]},
[2, 12],
[2, 12]
];
When I try to use the above code, it doesn't work. The error message is:
Uncaught TypeError: arr1.every is not a function
The final result should be:
console.log(repeatedArrays);
>>> [[1, 17], [2, 12], {from: [12, 0], to: [14, 5]}]
How can I make that code above work?
If you introduce a non array into the mix, you need to handle it differently.
Yours already work with array so I'm adding object style check for both sort and equal.
var arr = [
[1, 17],
[1, 17],
[1, 17],
[2, 12],
[5, 9],
[2, 12],
[6, 2],
{ from: [4, 30], to: [8, 21] },
{ from: [12, 0], to: [14, 5] },
{ from: [12, 0], to: [14, 5] },
{ from: [4, 30], to: [8, 20] },
{ from: [12, 0], to: [14, 5] },
{ from: [4, 30], to: [8, 20] },
[2, 12],
[2, 12]
];
arr.sort((a, b) => {
if (a instanceof Array && b instanceof Array) {
return a[0] - b[0] || a[1] - b[1]
} else if (a instanceof Array || b instanceof Array) {
return a instanceof Array ? -1 : 1
} else {
return a.from[0] - b.from[0] || a.from[1] - b.from[1] || a.to[0] - b.to[0] || a.to[1] - b.to[1]
}
});
// define equal for array
const equal = (arr1, arr2) => {
if (arr1 instanceof Array) {
return arr1.every((n, j) => n === arr2[j]);
} else {
if (arr2 instanceof Array) return false;
for (let k in arr1) {
if (!arr1[k].every((n, j) => n === arr2[k][j])) {
return false
}
}
return true;
}
};
let GROUP_SIZE = 3;
(first = 0), (last = 1), (res = []);
while (last < arr.length) {
if (equal(arr[first], arr[last])) last++;
else {
if (last - first >= GROUP_SIZE) res.push(arr[first]);
first = last;
}
}
if (last - first >= GROUP_SIZE) res.push(arr[first]);
console.log(res);
You can use the function reduce for grouping and counting the objects and then execute the function filter for getting the object with count >= 3.
var array = [ [1, 17], [1, 17], [1, 17], [2, 12], [5, 9], [2, 12], [6, 2], [2, 12], [2, 12] ];
let result = Object.values(array.reduce((a, [c, b]) => {
let key = `${c}|${b}`;
(a[key] || (a[key] = {count: 0, value: [c, b]})).count++;
return a;
}, {})).filter(o => {
if (o.count >= 3) {
delete o.count;
return true;
}
return false;
}).map(({value}) => value);
console.log(result);
.as-console-wrapper { min-height: 100%; }
Really simple - filter it all, then remove duplicates with Set and JSON methods (because it's nested arrays not objects):
var array = [
[1, 17],
[1, 17],
[1, 17],
[2, 12],
[5, 9],
[2, 12],
[6, 2],
[2, 12],
[2, 12]
];
var repeatedArrays = [...new Set(array.filter(e => array.filter(f => JSON.stringify(e.sort()) == JSON.stringify(f.sort()))).map(JSON.stringify))].map(JSON.parse);
console.log(repeatedArrays);
Related
Let's say I have an array of paired integers
let pairs = [
[6, 12],
[7, 6],
[8, 7],
[9, 8],
[12, 13],
[13, 14],
[14, 9]
];
All pairs creates chain by its nature, so you don't need to filter them.
So, the task is actually to build a chain from that, like
let output = [6, 12, 13, 14, 9, 8, 7];
It could be done by brute-forcing algorithm attached, but I am looking for more elegant solution.
let pairs = [
[6, 12],
[7, 6],
[8, 7],
[9, 8],
[12, 13],
[13, 14],
[14, 9]
];
let chain = [pairs[0][0], pairs[0][1]];
pairs.shift();
while(pairs.length !== 1){
let j = null;
for(let i = 0; i < pairs.length; i++){
if(pairs[i][0] === chain[chain.length - 1]) {
chain.push(pairs[i][1]);
j = i;
break;
}
if(pairs[i][1] === chain[chain.length - 1]){
chain.push(pairs[i][0]);
j = i;
break;
}
}
if(j !== null) { pairs.splice(j, 1); }
}
console.log(chain);
You should use a Map to iterate only once:
const pairs = [
[6, 12],
[7, 6],
[8, 7],
[9, 8],
[12, 13],
[13, 14],
[14, 9]
];
const pairsMap = new Map(pairs)
const chain = [pairs[0][0]]
for (let i = 0; i < pairs.length - 1; i++) {
const last = chain.at(-1)
const peer = pairsMap.get(last)
chain.push(peer)
}
console.log(chain)
The code below should work but it doesn't. Does anyone know why?
const items = [
["bob", 5],
["jeff", 2],
["wal-E", 2],
["bob", 1],
["bob", 10]
];
items.indexOf(["bob", 5]);
//=> -1
It does not because indexOf uses simple comparison when looking for a match and [] !== [] because arrays are compared by reference, not by their contents. Try typing [5]===[5] it will give you false.
So you will need to manually write comparison logic using findIndex.
let items = [
["bob", 5],
["jeff", 2],
["wal-E", 2],
["bob", 1],
["bob", 10]
];
console.log(items.findIndex(x => x[0] === "bob" && x[1] === 5))
Array#indexOf uses strict equality === for comparison. What you're wanting to do can only work if you hold a reference to the same array:
const x = [1, 2];
[[0, 1], [1, 2], [2, 3]].indexOf(x);
//=> -1
[[0, 1], x, [2, 3]].indexOf(x);
//=> 1
What you can do is use Array#findIndex and compare each element of each nested array with each element of x at the same index:
const indexOf = (xs, ys) => ys.findIndex(yy => {
if (xs.length != yy.length) return false;
return yy.reduce((b, y, i) => b && Object.is(y, xs[i]), true);
});
indexOf([], [[1],[],[2, 3]]);
//=> 1
indexOf([1, 2], [[1, 2, 3, 4], [1, 2, 3], [1, 2]]);
//=> 2
indexOf([1, 2], [[2, 3], [3, 4]]);
//=> -1
indexOf([9, 9, 9], [[9], [9, 9], [9, 9, 9]]);
//=> 2
indexOf([9, NaN, 9], [[9], [9, NaN, 9], [9, 9]]);
//=> 1
I try to loop the 2d arrays, but the I variable is undefined or not iterable, why?
can anyone tell me ??
function sum (arr) {
var total = 0
for(let [a1,a2,a3] of arr){
for(let i of [a1,a2,a3]){
for(let j of i){
total += j
}
}
if(typeof a2 == "undefined" && typeof a3 == "undefined"){
a2 = [0]
a3 = [0]
}
}
};
console.log(sum([
[
[10, 10],
[15],
[1, 1]
],
[
[2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
[4],
[9, 11]
],
[
[3, 5, 1],
[1, 5, 3],
[1]
],
[
[90]
]
]));
but when i sum another 2D array, it works, like this :
function sum (arr) {
var total = 0
for(let [a1,a2,a3] of arr){
for(let i of [a1,a2,a3]){
for(let j of i){
total += j
}
}
}
return total
}
console.log(sum([
[
[4, 5, 6],
[9, 1, 2, 10],
[9, 4, 3]
],
[
[4, 14, 31],
[9, 10, 18, 12, 20],
[1, 4, 90]
],
[
[2, 5, 10],
[3, 4, 5],
[2, 4, 5, 10]
]
]));
i try to loop 3 times for this 2d arrays, the first top code is each lengths are diffreen in array
and the last code is same,
Cause
let [a1,a2,a3] of [ [90] ])
will result in a2 and a3 being undefined, therefore in the following line it is:
for(const i of [90, undefined, undefined])
And at the second index it does:
for(let j of undefined)
which doesnt work.
You just need to move your if statement that checks if the value is undefined and assigns it to zero if it is ahead of the part of code that iterates over those values. You were getting this error because there wasn't anything there.
function sumTwo(arr) {
var total = 0
for(let [a1,a2,a3] of arr){
if(typeof a2 == "undefined" && typeof a3 == "undefined"){
a2 = [0]
a3 = [0]
}
for(let i of [a1,a2,a3]){
for(let j of i){
total += j
}
}
}
return total
};
console.log(sumTwo([
[
[10, 10],
[15],
[1, 1]
],
[
[2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
[4],
[9, 11]
],
[
[3, 5, 1],
[1, 5, 3],
[1]
],
[
[90]
]
])); //prints 237
When you say
let [a1,a2,a3] of [ [90] ])
there is no a2 or a3 there...
My suggestion would be using the code before you get into the first for loop:
if(arr.length < 3){
for(let y = arr.length, y > 3, y++ ){
arr.push(0)
}
}
Cheers!
It's probably better to recursively reduce the array using concat until you have a flat array and then reduce that to the sum of it's numbers:
const arr = [
[[10, 10], [15], [1, 1]],
[[2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], [4], [9, 11]],
[[3, 5, 1], [1, 5, 3], [1]],
[[90]],
];
const flatten = (arr) => {
const recur = (result, item) =>
!Array.isArray(item)
? result.concat(item)
: result.concat(item.reduce(recur, []));
return arr.reduce(recur, []);
};
console.log(
flatten(arr).reduce((result, item) => result + item, 0),
);
Definition:Creates an array of grouped elements, the first of which contains the first elements of the given arrays, the second of which contains the second elements of the given arrays, and so on.
Current Solution:
const zip = (...arr) => {
let maxLength = 0
let res = []
for (let el of arr) {
maxLength = Math.max(maxLength, el.length)
}
for (let j = 0; j < maxLength; j++) {
const foo = []
for (let n of arr) {
foo.push(n[j])
}
res.push(foo)
}
return res
}
Test Case:
test(('zip', () => {
expect(zip([1, 2], [4, 5], [9, 1])).toEqual([[1, 4, 9], [2, 5, 1]])
}
test('zip', () => {
expect(zip([1, 2, 3], [4, 5, 6])).toEqual([[1, 4], [2, 5], [3, 6]])
})
test('zip', () => {
expect(zip([1, 2], [], [3, 4, 5])).toEqual([
[1, undefined, 3],
[2, undefined, 4],
[undefined, undefined, 5],
])
})
I want to get a better way to achieve zip, current solution is ugly
See Destructuring Assignment and Array.prototype.map for more info.
// Proof.
const zip = (...args) => [...new Array(Math.max(...args.map(arr => arr.length)))].map((x, i) => args.map((y) => y[i]))
// Proof.
console.log(zip([1, 2], [4, 5], [9, 1])) // [[1, 4, 9], [2, 5, 1]]
console.log(zip([1, 2, 3], [4, 5, 6])) // [[1, 4], [2, 5], [3, 6]]
console.log(zip([1, 2], [], [3, 4, 5])) // [[1, undefined, 3], [2, undefined, 4], [undefined, undefined, 5]]
I have an array which can be nested multiple times. However, always two arrays with two entries each are at the end of each "nesting". I always need the two entries from the two arrays at the end of each nesting returned.
Here is an example:
const arr = [
[
[1, 2], [3, 4]
], [
[5, 6], [7, 8]
], [
[
[9, 10], [11, 12]
], [
[14, 15], [16, 17]
]
]
];
Here is the expected result:
const return1 = [
{ a: 1, b: 2 },
{ a: 3, b: 4 }
];
const return2 = [
{ a: 5, b: 6 },
{ a: 7, b: 8 }
];
const return3 = [
{ a: 9, b: 10 },
{ a: 11, b: 12 }
];
const return4 = [
{ a: 13, b: 14 },
{ a: 15, b: 16 }
];
Everything I find online is how to reduce an n-nested array to a flat array, something like this:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
You could map with an iterative and recursive approach while checking nested arrays.
var array = [[[1, 2], [3, 4]], [[5, 6], [7, 8]], [[[9, 10], [11, 12]], [[14, 15], [16, 17]]]],
result = array.reduce(function iter(r, a) {
return r.concat(Array.isArray((a[0] || [])[0])
? a.reduce(iter, [])
: [a.map(([a, b]) => ({ a, b }))]
);
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
With custom recursive function:
var arr = [[[1, 2], [3, 4]], [[5, 6], [7, 8]], [[[9, 10], [11, 12]], [[14, 15], [16, 17]]]],
result = [],
get_pairs = function(arr, r){
arr.forEach(function(v){
if (Array.isArray(v)) {
if (!Array.isArray(v[0])) {
var o = {a: v[0], b: v[1]};
(!r.length || r[r.length-1].length==2)? r.push([o]) : r[r.length-1].push(o);
} else {
get_pairs(v, r);
}
}
});
};
get_pairs(arr, result);
console.log(result);
Spent to much time in this. However, here is a very messy looking code.
There is this recursive function that checks if a given array is in the form [[number, number],[number, number]]. If so, it adds an object to the variable returnArray that we are knowingly mutating.
If it is not in the form, we just check for the items inside the array.
const arrInput = [
[[1, 2], [3, 4]],
[[5, 6], [7, 8]],
[
[[9, 10], [11, 12]],
[[14, 15], [16, 17]],
],
];
function mapArrayToObj(arr, returnArray = []) {
if (arr.length === 2 && typeof arr[0][0] === "number" &&
typeof arr[0][1] === "number" && typeof arr[1][0] === "number" &&
typeof arr[1][1] === "number") {
returnArray.push([
{ a: arr[0][0], b: arr[0][1] },
{ a: arr[1][0], b: arr[1][1] }
]);
} else {
arr.forEach((item) => { mapArrayToObj(item, returnArray); });
}
return returnArray;
}
console.log(mapArrayToObj(arrInput));