JavaScript - transform this data structure - javascript

When I have this array with this data structure:
[[3, 16, 1]
[3, 17, 1]
[3, 18, 1]
[3, 19, 1]
[3, 20, 1]
[3, 19, 1]
[3, 21, 1]
[3, 23, 1]
[3, 16, 1]
[3, 17, 1]
[2, 24, 1]
[2, 25, 1]
[2, 26, 1]
[2, 24, 1]]
and I want to count array elements and multiply this to the last number of the array, like this:
[[3, 16, 2]
[3, 17, 2]
[3, 18, 1]
[3, 19, 2]
[3, 20, 1]
[3, 21, 1]
[3, 23, 1]
[2, 24, 2]
[2, 25, 1]
[2, 26, 1]]
I tried to do it with:
array.forEach(function(x) {
counts[x] = (counts[x] || 0)+1;
});
but this changes the data structure, is there another form to do it?

I rewrite your function and console.log the output you want.
Whenever I check a new array, I store it in checkedArr and will check against it to prevent duplicate records.
const arr = [
[3, 16, 1],
[3, 17, 1],
[3, 18, 1],
[3, 19, 1],
[3, 20, 1],
[3, 19, 1],
[3, 21, 1],
[3, 23, 1],
[3, 16, 1],
[3, 17, 1],
[2, 24, 1],
[2, 25, 1],
[2, 26, 1],
[2, 24, 1],
];
const checkedArr = [];
const output = [];
for (let i = 0; i < arr.length; i++) {
let count = 0;
if (!isArrayChecked(arr[i])) {
checkedArr.push(arr[i]);
for (let j = i; j < arr.length; j++) {
if (isArraySame(arr[i], arr[j])) {
count++;
}
}
output.push([arr[i][0], arr[i][1], count]);
}
}
function isArrayChecked(array) {
let exist = false;
for (let k = 0; k < checkedArr.length; k++) {
if (isArraySame(array, checkedArr[k])) {
exist = true;
break;
}
}
return exist;
}
function isArraySame(arr1, arr2) {
if (arr1[0] !== arr2[0] || arr1[1] !== arr2[1] || arr1[2] !== arr2[2])
return false;
return true;
}
console.log(output);

The problem with your code is in counts[x]. You can't use an array to index an object.
You can solve the issue by stringifying the array. That is, use:
counts[String(x)] = (counts[String(x)] || 0)+1;

let arr=[
[3, 16, 1],
[3, 17, 1],
[3, 18, 1],
[3,16,1],
[3, 19, 1],
[3, 20, 1],
[3, 19, 1],
[3, 21, 1],
[3, 23, 1],
[3, 16, 1],
[3, 17, 1],
[2, 24, 1],
[2, 25, 1],
[2, 26, 1],
[2, 24, 1]]
let solution = (arr) => {
let obj = {};
let result = [];
for (let i of arr) {
let keyOfObj = JSON.stringify(i);
obj[keyOfObj] ? obj[keyOfObj]++ : obj[keyOfObj] = 1;
}
for (let [key, value] of Object.entries(obj)) {
let objKeyArr = JSON.parse(key);
if (value >= 2) {
let lastElemt = objKeyArr[objKeyArr.length - 1];
objKeyArr.splice(objKeyArr.length - 1, 1, lastElemt * value);
result.push(objKeyArr);
} else {
result.push(objKeyArr);
}
}
return result;
};
solution(arr)

Related

picking a unique set from an array of arrays

I attempted to ask a more complicated of this before but I couldn't explain it well so I am trying again with a simplified use case.
I will have an array of arrays like the following
var allData = [[1,2,3,4,5],[1,2,3,4,5],[1,2,3,4,5],[1,2,3,4,5],[1,2,3,4,5]]
I need to select 1 element from each array so that I get a unique set like [2,4,1,3,5] easy to do in this case as each array has all values. However this will rarely be the case. Instead I may have
var allData = [[1,2,4],[1,2],[1,2],[2,4,5],[1,2,3,5]]
In this case I couldn't pick 1 or 2 from the first array as that would prevent the 2nd and 3rd from having a unique combination. So something like [4,2,1,5,3] or [4,1,2,5,3] would be the only two possible answers for this combination.
The only way I see to do this is to just go through every combination but these will get fairly large so it doesn't seem reasonable as this happens real time. There are going to be at least 7 arrays, possibly 14 and distantly possible to have 31 so going through every combination would be fairly rough.
The 2nd part is if there is some way to "know" you have the best possible option. Say if there was some way I would know that having a single duplicate is my best case scenario. Even if I have to brute force it if I encounter a 1 duplication solution I would know to stop.
One easy way to get a very simple of this is to just subtract the number of possible choices from the number of elements but this is the correct answer in only the simplest of cases. Is there some type of library or anything to help solve these types of problems? It is a bit beyond my math abilities.
Here is something I have tried but it is too slow for larger sets and can fail. It works sometimes for the 2nd case I presented but only on luck
const allData = [[1,2,4],[1,2],[1,2],[2,4,5],[1,2,3,5]]
var selectedData = []
for (var i in allData){
console.log("length",allData[i].length)
var j = 0
while(j < allData[i].length){
console.log("chekcing",allData[i][j])
if (selectedData.includes(allData[i][j])){
console.log("removing item")
allData[i].splice(j,1)
}
else{j++}
}
var uniqueIds = Object.keys(allData[i])
console.log(uniqueIds)
var randId = Math.floor(Math.random() * uniqueIds.length)
console.log(randId)
selectedData.push(allData[i][randId])
console.log("selectedData",selectedData)
}
You can start with a fairly simple backtracking algorithm:
function pick(bins, n = 0, res = {}) {
if (n === bins.length) {
return res
}
for (let x of bins[n]) {
if (!res[x]) {
res[x] = n + 1
let found = pick(bins, n + 1, res)
if (found)
return found
res[x] = 0
}
}
}
//
let a = [[1, 2, 4], [1, 2], [1, 2], [2, 4, 5], [1, 2, 3, 4]]
console.log(pick(a))
This returns a mapping item => bin index + 1, which is easy to convert back to an array if needed.
This should perform relatively well for N < 10, for more/larger bins you can think of some optimizations, for example, avoid the worst case scenario by sorting bins from smallest to longest, or, depending on the nature of elements, represent bins as bitmasks.
You could count all elements and take various comparison with same indices.
function x([...data]) {
while (data.some(Array.isArray)) {
const
counts = data.reduce((r, a, i) => {
if (Array.isArray(a)) a.forEach(v => (r[JSON.stringify(v)] = r[JSON.stringify(v)] || []).push(i));
return r;
}, {}),
entries = Object.entries(counts),
update = ([k, v]) => {
if (v.length === 1) {
data[v[0]] = JSON.parse(k);
return true;
}
};
if (entries.some(update)) continue;
const grouped = entries.reduce((r, [, a]) => {
const key = JSON.stringify(a);
r[key] = (r[key] || 0) + 1;
return r;
}, {});
Object.entries(grouped).forEach(([json, length]) => {
const indices = JSON.parse(json);
if (indices.length === length) {
let j = 0;
indices.forEach(i => data[i] = data[i][j++]);
return;
}
if (length === 1) {
const value = JSON.parse(entries.find(([_, a]) => JSON.stringify(a) === json)[0]);
indices.forEach(i => data[i] = data[i].filter(v => v !== value));
data[indices[0]] = value;
}
});
}
return data;
}
console.log(...x([[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]]));
console.log(...x([[1, 2, 4], [1, 2], [1, 2], [2, 4, 5], [1, 2, 3, 5]]));
console.log(...x([[1, 2, 4], [1, 2], [1, 2], [2, 4, 5], [1, 2, 3, 5], [6, 7, 8, 9], [6, 7, 8, 9], [6, 7, 8, 10], [6, 7, 8, 10], [6, 7, 8, 10]]));
Here is an implementation based around counting occurrences across the arrays.
It first creates a map indexed by value counting the number of inner arrays each value occurs in. It then sorts by inner array length to prioritize shorter arrays, and then iterates over each inner array, sorting by occurrence and selecting the first non-duplicate with the lowest count, or, if there are no unique values, the element with the lowest count.
const
occurrencesAcrossArrays = (arr) =>
arr
.reduce((a, _arr) => {
[...new Set(_arr)].forEach(n => {
a[n] = a[n] || 0;
a[n] += 1;
});
return a;
}, {}),
generateCombination = (arr) => {
const dist = occurrencesAcrossArrays(arr)
return arr
.sort((a, b) => a.length - b.length)
.reduce((a, _arr) => {
_arr.sort((a, b) => dist[a] - dist[b]);
let m = _arr.find(n => !a.includes(n));
if (m !== undefined) {
a.push(m);
} else {
a.push(_arr[0]);
}
return a;
}, []);
};
console.log(generateCombination([[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]]).toString());
console.log(generateCombination([[1, 2, 4], [1, 2], [1], [2, 4, 5], [1, 2, 3, 5]]).toString());
console.log(generateCombination([[1, 2, 4], [1, 2], [1, 2], [2, 4, 5], [1, 2, 3, 5], [6, 7, 8, 9], [6, 7, 8, 9], [6, 7, 8, 10], [6, 7, 8, 10], [6, 7, 8, 10]]).toString());
Edit
In response to your comment – The situation seems to be emerging because the values all have the same occurrence count and are sequential.
This can be solved by keeping a running count of each value in the result array, and sorting each inner array by both by this running occurrence count as well as the original distribution count.This adds complexity to the sort, but allows you to simply access the first element in the array (the element with the lowest rate of occurrence in the result with the lowest occurrence count across all arrays).
const
occurrencesAcrossArrays = (arr) =>
arr
.reduce((a, _arr) => {
[...new Set(_arr)].forEach(n => {
a[n] = a[n] || 0;
a[n] += 1;
});
return a;
}, {}),
generateCombination = (arr) => {
const dist = occurrencesAcrossArrays(arr)
return arr
.sort((a, b) => a.length - b.length)
.reduce((acc, _arr) => {
_arr.sort((a, b) => (acc.occurrences[a] || 0) - (acc.occurrences[b] || 0) || dist[a] - dist[b]);
let m = _arr[0]
acc.occurrences[m] = acc.occurrences[m] || 0;
acc.occurrences[m] += 1;
acc.result.push(m);
return acc;
}, { result: [], occurrences: {} })
.result; // return the .result property of the accumulator
};
console.log(generateCombination([[2, 3, 4, 5, 6], [2, 3, 4, 5, 6], [2, 3, 4, 5, 6], [2, 3, 4, 5, 6], [2, 3, 4, 5, 6], [2, 3, 4, 5, 6], [2, 3, 4, 5, 6]]).toString());
// 2,3,4,5,6,2,3
console.log(generateCombination([[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]]).toString());
// 1,2,3,4,5
console.log(generateCombination([[1, 2, 4], [1, 2], [1], [2, 4, 5], [1, 2, 3, 5]]).toString());
// 1,2,4,5,3
console.log(generateCombination([[1, 2, 4], [1, 2], [1, 2], [2, 4, 5], [1, 2, 3, 5], [6, 7, 8, 9], [6, 7, 8, 9], [6, 7, 8, 10], [6, 7, 8, 10], [6, 7, 8, 10]]).toString());
//1,2,4,5,3,9,6,10,7,8
console.log(generateCombination([[1], [2, 3,], [3, 4, 5], [3, 4, 5, 6], [2, 3, 4, 5, 6, 7]]).toString());
// 1,2,4,6,7
A note on .reduce()
If you're having trouble getting your head around .reduce() you can rewrite all the instances of it in this example using .forEach() and declaring accumulator variables outside of the loop. (This will not always be the case, depending on how you manipulate the accumulator value within a reduce() call).
Example below:
const occurrencesAcrossArrays = (arr) => {
const occurrences = {};
arr.forEach(_arr => {
[...new Set(_arr)].forEach(n => {
occurrences[n] = occurrences[n] || 0;
occurrences[n] += 1;
});
});
return occurrences;
};
const generateCombination = (arr) => {
const dist = occurrencesAcrossArrays(arr);
const result = [];
const occurrences = {};
arr.sort((a, b) => a.length - b.length);
arr.forEach(_arr => {
_arr.sort((a, b) => (occurrences[a] || 0) - (occurrences[b] || 0) || dist[a] - dist[b]);
let m = _arr[0]
occurrences[m] = occurrences[m] || 0;
occurrences[m] += 1;
result.push(m);
});
return result;
};
console.log(generateCombination([[2, 3, 4, 5, 6], [2, 3, 4, 5, 6], [2, 3, 4, 5, 6], [2, 3, 4, 5, 6], [2, 3, 4, 5, 6], [2, 3, 4, 5, 6], [2, 3, 4, 5, 6]]).toString());
// 2,3,4,5,6,2,3
console.log(generateCombination([[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]]).toString());
// 1,2,3,4,5
console.log(generateCombination([[1, 2, 4], [1, 2], [1], [2, 4, 5], [1, 2, 3, 5]]).toString());
// 1,2,4,5,3
console.log(generateCombination([[1, 2, 4], [1, 2], [1, 2], [2, 4, 5], [1, 2, 3, 5], [6, 7, 8, 9], [6, 7, 8, 9], [6, 7, 8, 10], [6, 7, 8, 10], [6, 7, 8, 10]]).toString());
//1,2,4,5,3,9,6,10,7,8
console.log(generateCombination([[1], [2, 3,], [3, 4, 5], [3, 4, 5, 6], [2, 3, 4, 5, 6, 7]]).toString());
// 1,2,4,6,7
You could solve this problem using a MILP-model. Here is one implementation in MiniZinc (data has been extended to seven days):
int: Days = 7;
int: Items = 5;
set of int: DAY = 1..Days;
set of int: ITEM = 1..Items;
array[DAY, ITEM] of 0..1: A = % whether item k is allowed on day i
[| 1, 1, 0, 1, 0
| 1, 1, 0, 0, 0
| 1, 1, 0, 0, 0
| 0, 1, 0, 1, 1
| 1, 1, 0, 0, 0
| 0, 1, 0, 1, 1
| 1, 1, 1, 0, 1 |];
array[DAY, ITEM] of var 0..1: x; % 1 if item selected k on day i, otherwise 0
array[DAY, DAY, ITEM] of var 0..1: w; % 1 if item k selected on both day i and day j, otherwise 0
% exactly one item per day
constraint forall(i in DAY)
(sum(k in ITEM)(x[i, k]) = 1);
% linking variables x and w
constraint forall(i, j in DAY, k in ITEM where i < j)
(w[i, j, k] <= x[i, k] /\ w[i, j, k] <= x[j, k] /\ w[i, j, k] >= x[i, k] + x[j, k] - 1);
% try to minimize duplicates and if there are duplicates put them as far apart as possible
var int: obj = sum(i, j in DAY, k in ITEM where i < j)(((Days - (j - i))^2)*w[i, j, k]);
solve minimize obj;
output
["obj="] ++ [show(obj)] ++
["\nitem="] ++ [show([sum(k in ITEM)(k*x[i, k]) | i in DAY])];
Running gives:
obj=8
item=[2, 1, 5, 4, 3, 2, 1]
The following package looks promising for a JavaScript implementation: https://www.npmjs.com/package/javascript-lp-solver

Array algorithm: How to reform this nested array use javascript?

I have a table like this:
The colored blocks have coordinates as an array:
[
[1, 1],
[2, 1],
[2, 4],
[2, 5],
[3, 2],
[3, 4],
[4, 4],
[4, 5],
[4, 6],
[4, 7],
[5, 3],
[6, 3],
[6, 4],
[6, 5]
]
Now I want to group the neighboring blocks (horizontal and vertical) to independent child array.
The output estimated is like:
[
[
[1, 1],
[2, 1]
],
[
[2, 4],
[2, 5],
[3, 4],
[4, 4],
[4, 5],
[4, 6],
[4, 7]
],
[
[3, 2]
],
[
[5, 3],
[6, 3],
[6, 4],
[6, 5]
]
]
How to use a function to do this?
Edit: I tried to iterate each value in the input array and compare to [1, 1], if one of the coordinate is the same, push them to an new array and delete in the input array, and use recursion to do this again. But I stuck by a problem...as I should group [2, 5] and [4, 5] but cannot group [4, 4] and [6, 4]
You could filter the grouped items and build a new group with the own indices.
const
data = [[1, 1], [2, 1], [2, 4], [2, 5], [3, 2], [3, 4], [4, 4], [4, 5], [4, 6], [4, 7], [5, 3], [6, 3], [6, 4], [6, 5]],
offsets = [[-1, 0], [1, 0], [0, -1], [0, 1]],
groups = data.reduce((r, [i, j]) => {
const
own = [];
temp = r.filter(group => {
const found = group.some(g => offsets.some(o => i + o[0] === g[0] && j + o[1] === g[1]));
if (!found) return true;
own.push(...group);
});
return [...temp, [...own, [i, j]]];
}, []);
console.log(groups);
.as-console-wrapper { max-height: 100% !important; top: 0; }
It seems to me that you are having just a logic problem, not a JavaScript, since you know how to nest the array, is just having a problem to find the right logic to group neighbors.
You can't just compare one part of the coordinate, since the other can me really distant. You need to compare both. If you want to find the neighbor coordinate you need to have one part of the coordinate equal and the another part exactly with 1 distance away.
var arr =
[
[1, 1],
[2, 1],
[2, 4],
[2, 5],
[3, 2],
[3, 4],
[4, 4],
[4, 5],
[4, 6],
[4, 7],
[5, 3],
[6, 3],
[6, 4],
[6, 5]
];
var groupedArr = new Array();
for(i = 0; i < arr.length; i++)
{
var grouped = false;
for(j = 0; j < groupedArr.length; j++)
{
for(k = 0; k < groupedArr[j].length; k++)
{
if((arr[i][0] == groupedArr[j][k][0] && Math.abs(arr[i][1] - groupedArr[j][k][1]) == 1)
|| (arr[i][1] == groupedArr[j][k][1] && Math.abs(arr[i][0] - groupedArr[j][k][0]) == 1))
{
groupedArr[j].push(arr[i]);
grouped = true;
break;
}
}
if(grouped)
break;
}
if(!grouped)
{
var newGroup = new Array();
newGroup.push(arr[i]);
groupedArr.push(newGroup);
}
}
console.log(groupedArr);
looks like clustering problem. But we can solve with this simple code for small data.
ax = [[1, 1], [2, 1], [2, 4], [2, 5], [3, 2], [3, 4], [4, 4], [4, 5], [4, 6], [4, 7], [5, 3], [6, 3], [6, 4], [6, 5]];
console.log(JSON.stringify(reForm(ax)));
function reForm(a) {
const ret = [];
while (a.length > 0) {
var sub = [a.shift()];
var i=0;
while (i<sub.length){
var j=0
while(j<a.length){
if((a[j][0]==sub[i][0] && Math.abs(a[j][1]-sub[i][1])==1) ||
(a[j][1]==sub[i][1] && Math.abs(a[j][0]-sub[i][0])==1))
sub.push(...a.splice(j,1));
else j++
}
i++;
}
ret.push(sub);
}
return ret;
}
You can do this by using recursion
var array =[
[1, 1],
[2, 1],
[2, 4],
[2, 5],
[3, 2],
[3, 4],
[4, 4],
[4, 5],
[4, 6],
[4, 7],
[5, 3],
[6, 3],
[6, 4],
[6, 5]
]
var returnval = new Array();
while(array.length>0)
{
var temp = new Array();
var item = array[0];
array.splice(0, 1);
temp.push(item);
findnext(item,temp);
returnval.push(temp);
}
console.log(returnval);
function findnext(item, temp)
{
for(var i=0;i<array.length;i++)
{
if((array[i][0]==item[0] && Math.abs(array[i][1]-item[1])==1) || (array[i][1]==item[1] && Math.abs(array[i][0]-item[0])==1))
{
temp.push(array[i]);
item1 = array[i];
array.splice(i,1);
findnext(item1, temp);
}
}
}

Find if arrays repeat and then select them [closed]

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);

Why my variable is not iterable when i loop

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),
);

check and compare 2 arrays

function calWinner(arr) {
//winning combination
const winningIds = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6],
]
for (let i = 0; i < winningIds.length; i++) {
calculate(arr, winningIds[i])
}
}
function calculate(sup, sub) {
sup.sort()
sub.sort()
let i = 0
let j = 0
for (i, j; i < sup.length && j < sub.length;) {
if (sup[i] < sub[j]) {
++i
} else if (sup[i] == sub[j]) {
++i, ++j
} else {
return false
}
}
return j == sub.length;
}
calWinner([1, 3, 7, 4])
I'm trying to write a function that takes an array, and check if it has every element in a nested array in an object inside of the function.
I've added a function I found from this post, but not sure why i am getting undefined instead of true.
Assuming you want to return true if any array from winningIds is inside arr, this is the code:
function calWinner(arr) {
//winning combination
const winningIds = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6],
]
var containsWinner = false;
for (let i = 0; i < winningIds.length && !containsWinner; i++) {
containsWinner = calculate(arr, winningIds[i])
}
return containsWinner;
}
function calculate(sup, sub) {
sup.sort()
sub.sort()
for (var i = 0; i < sub.length; i++) {
if (sup.indexOf(sub[i]) == -1) {
return false;
}
}
return true;
}
calWinner([1, 3, 7, 4]);

Categories