Here are the variables:
let linked = {
related: [
[0, 'a', 'b'],
[0, 'c', 'd', 'e', 'f', 'g'],
[0, "s"],
[0, 'd'],
[0, 'g', 'n', 'h']
]
}
let hold = [{
0: 4, // 0 represents [0,'a','b']
1: 3 // 1 represents [0,'c','d','e','f','g']
},
{
3: 2, // 3 represents [0,'d']
4: 6 // 4 represents [0,'g','n', 'h']
}
];
The hold array contains two objects and each object's property represents index of link.related .
The problem is I want to add values of each hold object property to the first element of linked.related.
So the result should be:
let linked = {
related: [
[4, 'a', 'b'],
[3, 'c', 'd', 'e', 'f', 'g'],
[0, "s"],
[2, 'd'],
[6, 'g', 'n', 'h']
]
}
So I want to sum values of hold with the first element of linked.related
You can do it in 2 forEach loops
hold.forEach(x => {
Object.keys(x).forEach (y => {
linked.related[y][0] += x[y]
});
});
let linked = {
related: [
[0, 'a', 'b'],
[0, 'c', 'd', 'e', 'f', 'g'],
[0, "s"],
[0, 'd'],
[0, 'g', 'n', 'h']
]
}
let hold = [{
0: 4,
1: 3
},
{
3: 2,
4: 6
}
];
hold.forEach(x => {
Object.keys(x).forEach (y => {
linked.related[y][0] += x[y]
});
});
console.log(linked.related);
You could iterate hold and get the entries for the update.
var linked = { related: [[0, 'a', 'b'], [0, 'c', 'd', 'e', 'f', 'g'], [0, "s"], [0, 'd'], [0, 'g', 'n', 'h']] },
hold = [{ 0: 4, 1: 3 }, { 3: 2, 4: 6 }];
hold.forEach(o => Object.entries(o).forEach(([i, v]) => linked.related[i][0] += v));
console.log(linked);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use forEach and Object.entries
let linked = {related: [[0, 'a', 'b'],[0, 'c', 'd', 'e', 'f', 'g'],[0, "s"],[0, 'd'],[0, 'g', 'n', 'h']]}
let hold =[{0: 4, 1:3},{3: 2, 4:6}]
hold.forEach(v => {
Object.entries(v).forEach(([k, v]) => {
linked.related[k][0] += v
})
})
console.log(linked)
Related
The target is to detect superstring in a set of arrays. In this case it should be 'bal' but I get 'lbal'.
const arr = [
['g', 'l', 'o', 'b', 'a', 'l'],
['b','a','l','l']
]
const res = argv.reduce((acc, val) => acc.filter(elem => val.includes(elem)))
This function just gives ALL duplicates(items that are presented in any array) when I need only the most long duplicate sequence. Any suggestions?
you can create an object that counts how many times an element is present in the array of array
like this
const arr = [
['a', 'b', 'm'],
['g', 'o', 'a', 'b'],
['w', 'o', 'u', 'k', 'a', 'b']
]
const countTimes = data => data.flat().reduce((res, v) => {
return {
...res,
[v]: (res[v] || 0 ) + 1
}
}, {})
const duplicates = data => Object.entries(countTimes(data))
.filter(([v, n]) => n > 1)
.map(([v, n]) => v)
console.log(countTimes(arr))
console.log(duplicates(arr) )
const original = [
['a', 'b', 'm'],
['g', 'o', 'a', 'b'],
['w', 'o', 'u', 'k', 'a', 'b']
]
// The easiest is to split up between unique results and duplicates
let uniqueValues = []
let duplicates = []
// Now we're going to loop every array
original.forEach((arr) => {
// Loop every value inside the array
arr.forEach((value) => {
// Check if we had this value already
if (!uniqueValues.includes(value)) {
uniqueValues.push(value)
} else {
duplicates.push(value)
}
})
})
console.log('Duplicates: ', duplicates)
// If you want remove the duplicates from the duplicates, use set
let uniqueDuplicates = [...new Set(duplicates)]
console.log('Unique duplicates: ', uniqueDuplicates)
If you don't have to know in which array duplicates are, you can use Array.prototype.flat() to get rid of nested arrays, then check simple array for duplicates.
const arr = [
['a', 'b', 'm'],
['g', 'o', 'a', 'b'],
['w', 'o', 'u', 'k', 'a', 'b']
]
const arr2 = arr.flat() // ['a', 'b', 'm', 'g', 'o', 'a', 'b', 'w', 'o', 'u', 'k', 'a', 'b']
const hasDuplicates = new Set(arr2).size !== arr2.length
you can create a tally, to find how many each element globally is duplicated by doing a nested forEach
function findDuplicates(data) {
const map = {};
data.forEach((row) => {
row.forEach((item) => {
if (!map[item]) {
map[item] = 1;
} else [map[item]++];
});
});
return map;
}
You can create a simple counter object (if you know python, this is similar to collections.Counter):
class Counter extends Map {
update(values) {
for (let val of values)
this.set(val, 1 + (this.get(val) ?? 0))
}
}
ARR = [
['a', 'b', 'm'],
['g', 'o', 'a', 'b'],
['w', 'o', 'u', 'k', 'a', 'b']
]
const tally = new Counter()
for (let subArray of ARR)
tally.update(new Set(subArray))
for (let [element, count] of tally)
if (count === ARR.length)
console.log(element)
count === yourArrayOfArrays.length selects elements that appear in all arrays, you can replace it with count > 1 to find any duplicates.
I need the solution for the general case
for example
let data = [['a', 'b'],['c', 'd'],['e', 'f', 'g', 'h']];
I need this:
{
"a": {
"c": {
"e": 0,
"f": 0,
"g": 0,
"h": 0
},
"d": {
"e": 0,
"f": 0,
"g": 0,
"h": 0
}
},
"b": {
"c": {
"e": 0,
"f": 0,
"g": 0,
"h": 0
},
"d": {
"e": 0,
"f": 0,
"g": 0,
"h": 0
}
}
}
and data can be any random array of arrays... I tried a recursive approach but I get stuck with Map and .fromEntries method...
Simple recursion:
Base case - we only have one array inside the array. We construct an object with default values from it.
Recursive step - we have more arrays. We build up an object and each key comes from the first array, each value is a recursive call that uses the rest of the arrays:
const buildObj = (data, defaultValue = 0) => {
if (data.length > 1)
return Object.fromEntries(
data[0].map(x => [x, buildObj(data.slice(1), defaultValue)])
)
return Object.fromEntries(
data[0].map(x => [x, defaultValue])
);
}
console.log(buildObj([
['e', 'f', 'g', 'h']
]));
console.log(buildObj([
['c', 'd'],
['e', 'f', 'g', 'h']
]));
console.log(buildObj([
['a', 'b'],
['c', 'd'],
['e', 'f', 'g', 'h']
]));
console.log(buildObj([
['a', 'b'],
['c', 'd'],
['e', 'f', 'g', 'h']
], 42)); //different default
Can also be represented by:
Base case - return the default value.
Recursive step - We build up an object and each key comes from the first array, each value is a recursive call that uses the rest of the arrays.
const buildObj = (data, defaultValue = 0) => {
if (data.length !== 0)
return Object.fromEntries(
data[0].map(x => [x, buildObj(data.slice(1), defaultValue)])
);
return defaultValue;
}
console.log(buildObj([
['e', 'f', 'g', 'h']
]));
console.log(buildObj([
['c', 'd'],
['e', 'f', 'g', 'h']
]));
console.log(buildObj([
['a', 'b'],
['c', 'd'],
['e', 'f', 'g', 'h']
]));
console.log(buildObj([
['a', 'b'],
['c', 'd'],
['e', 'f', 'g', 'h']
], 42)); //different default
I think this runs good. Runs recursion with step. You can change forEach to for loop, if you want.
let data = [['a', 'b'],['c', 'd'],['e', 'f', 'g', 'h']];
const arrToDict = (data) => {
const recursive = (depth = 0) => {
let dict = {}
if (data.length === depth + 1) {
data[depth].forEach(el => {
dict[el] = 0
})
} else {
data[depth].forEach(el => {
dict[el] = recursive(depth+1)
})
}
return dict
}
return recursive();
}
arrToDict(data)
I have used a recursion for converting each index to object and then used Memoization for a more efficient solution
Base Case: When the index has gone out of bounds of current array
Recursive Case: recurse over the next index and assign the next objectified index as a value to the current key
//store the index which is already iterated/objectified
//this is just for LESS COMPUTATION and MORE EFFICIENCY
const memoizeObjectifiedIndex = {};
let data = [['a', 'b'],['c', 'd'],['e', 'f', 'g', 'h']];
//basic recursive approach
function createObject(data,index){
//base case,
//if the index is just outside the length of array,
//here that index=3, since array is 0 indexed and last index is 2
if(index === data.length) return 0;
//check in memoized object if current index is already objectfied
if(memoizeObjectifiedIndex[index]){
//you can check the hits when this condition is true and COMPUTATION is saved
// console.log("Found for index ", index);
return memoizeObjectifiedIndex[index];}
const obj={};
data[index].forEach((key) => {
//assign the next objectified index as value to current key
obj[key] = createObject(data,index+1);
})
//store the object for current index for future use
memoizeObjectifiedIndex[index] = obj;
return obj;
}
console.log(createObject(data,0))
Note: You can see better output by copying and running this code in browser console.
I have two arrays that represent a fifo-like state, an old state and a new state. I need a function that finds the newly added items by comparing the new array with the old one. Below 3 examples of two arrays where 1 has items added to the front of it compared to the other:
// Input 1
const arr1 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'];
const arr2 = ['a', 'b', 'a', 'b', 'c', 'd', 'e', 'f', 'g']; // added 'a' and 'b' in front
// Input 2
const arr3 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'];
const arr4 = ['q', 'r', 'a', 'b', 'c', 'd', 'e', 'f', 'g']; // added 'q' and 'r' in front
// Input 3
const arr5 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'];
const arr6 = ['a', 'b', 'q', 'a', 'b', 'c', 'd', 'e', 'f']; // added 'a' 'b' and 'q' in front
// New Input 4
const arr7 = ['a', 'b', 'a', 'b', 'c', 'd', 'e', 'f', 'g'];
const arr8 = ['a', 'b', 'a', 'b', 'a', 'b', 'c', 'd', 'e']; // added 'a' and 'b' in front
Note that the amount of newly added items is removed from the back of the array.
Here the desired functionality getItemsAdded(arr1, arr2) function:
// Desired output for 'getItemsAdded()' function
console.log(getItemsAdded(arr1, arr2)); // [ 'a', 'b' ]
console.log(getItemsAdded(arr3, arr4)); // [ 'q', 'r' ]
console.log(getItemsAdded(arr5, arr6)); // [ 'a', 'b', 'q' ]
// New
console.log(getItemsAdded(arr7, arr8)); // [ 'a', 'b' ]
It feels like such a simple problem, but I cant get my head around it.. I couldn't solve it with solutions provided here How to get the difference between two arrays in JavaScript?, since its a different problem.
Code can tell more words, Then my silly explanation...
// Input 1
const arr1 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'];
const arr2 = ['a', 'b', 'a', 'b', 'c', 'd', 'e', 'f', 'g']; // added 'a' and 'b' in front
// Input 2
const arr3 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'];
const arr4 = ['q', 'r', 'a', 'b', 'c', 'd', 'e', 'f', 'g']; // added 'q' and 'r' in front
// Input 3
const arr5 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'];
const arr6 = ['a', 'b', 'q', 'a', 'b', 'c', 'd', 'e', 'f']; // added 'a' 'b' and 'q' in front
const arr7 = ['a', 'b', 'a', 'b', 'c', 'd', 'e', 'f', 'g'];
const arr8 = ['a', 'b', 'a', 'b', 'a', 'b', 'c', 'd', 'e']; // added 'a' and 'b' in front
// Desired output for 'diff()' function
console.log([...getItemsAdded(arr1, arr2)]); // [ 'a', 'b' ]
console.log([...getItemsAdded(arr3, arr4)]); // [ 'q', 'r' ]
console.log([...getItemsAdded(arr5, arr6)]); // [ 'a', 'b', 'q' ]
console.log([...getItemsAdded(arr7, arr8)]); // [ 'a', 'b' ]
function startsWith(arr1, arr2) {
for (let i = 0; i < arr1.length; i++)
if (arr1[i] != arr2[i])
return false
return true
}
function* getItemsAdded(arr1, arr2) {
while (!startsWith(arr2, arr1)) yield arr2.shift()
}
I have an array that is currently sorted by the first value:
[ [ 'a', 3 ],
[ 'c', 3 ],
[ 'd', 1 ],
[ 'e', 2 ],
[ 'f', 1 ],
[ 'g', 1 ],
[ 'i', 7 ],
[ 'l', 3 ],
[ 'o', 2 ],
[ 'p', 2 ],
[ 'r', 2 ],
[ 's', 3 ],
[ 't', 1 ],
[ 'u', 2 ],
[ 'x', 1 ] ]
I would like to sort the digits in descending order to get:
[ [ 'i', 7 ],
[ 'a', 3 ],
[ 'c', 3 ],
[ 'l', 3 ],
[ 's', 3 ],
[ 'e', 2 ],
[ 'o', 2 ] ......]
Use Array.sort([compareFunction])
function comparator(a, b) {
if (a[1] > b[1]) return -1
if (a[1] < b[1]) return 1
return 0
}
myArray = myArray.sort(comparator)
edit for comment:
Here is a jslint showing it in action:
https://jsfiddle.net/49ed0Lj4/1/
The sort method in Array
var arr = [
['a', 3],
['c', 3],
['d', 1],
['e', 2],
['f', 1],
['g', 1],
['i', 7],
['l', 3],
['o', 2],
['p', 2],
['r', 2],
['s', 3],
['t', 1],
['u', 2],
['x', 1]
];
arr.sort(function(a, b) {
return b[1] - a[1]
})
Maybe you need to sort by both the English letters and number. You can change the callback function to do this.
I need help converting several arrays:
x = ['a', 'b', 'c']
y = ['d', 'e', 'f']
z = ['d', 'g', 'h']
Into a single JSON:
{
a: { b: { c: 'done' }},
d: { e: { f: 'done' },
g: { h: 'done' }}
}
Is this possible using recursion? I can't seem to get it working properly so I was wondering if there is already an easy way to do this in JS.
var struct = {};
var paths = [
['a', 'b', 'c'],
['d', 'e', 'f'],
['d', 'g', 'h']
];
paths.forEach(function (path) {
var ref;
ref = struct;
path.forEach(function (elem, index) {
if (!ref[elem]) {
ref[elem] = index === path.length - 1 ? "done": {};
}
ref = ref[elem];
});
});
console.log(JSON.stringify(struct, null, "\t"));
Output:
{
"a": {
"b": {
"c": "done"
}
},
"d": {
"e": {
"f": "done"
},
"g": {
"h": "done"
}
}
}
Note: this script will fail if your input is like:
var paths = [
['a', 'b', 'c'],
['a', 'b', 'c', 'd' ]
];
It decided c should be "done" but then there is another level. maybe this wont ever happen, if it does, figure out what you want the result to be.
A version with Array#forEach() and Array#reduce()
var x = ['a', 'b', 'c'],
y = ['d', 'e', 'f'],
z = ['d', 'g', 'h'],
object = function (array) {
var o = {};
array.forEach(function (a) {
var last = a.pop();
a.reduce(function (r, b) {
r[b] = r[b] || {};
return r[b];
}, o)[last] = 'done';
});
return o;
}([x, y, z]);
document.write('<pre>' + JSON.stringify(object, 0, 4) + '</pre>');