value has been overrite in nested forLoop issue - javascript

I am not sure what' wrong with my code, value has been override in the nested for-loop, please help me debug following code. var1 is an array that contains another array called list. Var2 is also an array, and each var2.data is equal to the var1. I tried to setup the list.id = var2.index of each var2.data, but for some reason that all the list.id inside of var2 are equal 2, seems like that value has been override. Please see below:
let var1 = [{
'name': 'name1',
'list': [{
id: 0,
a: "test1",
b: 'test2'
},
{
id: 0,
a: "aac",
b: 'test2'
},
{
id: 0,
a: "aad",
b: 'test2'
},
]
},
{
'name': 'name2',
'list': [{
id: 0,
a: "test1",
b: 'test2'
},
{
id: 0,
a: "aac",
b: 'test2'
},
{
id: 0,
a: "aad",
b: 'test2'
},
]
}
];
let var2 = [{
claim: 'claim1',
ifn: '1',
data: []
},
{
claim: 'claim2',
ifn: '2',
data: []
},
{
claim: 'claim3',
ifn: '3',
data: []
},
]
var2.forEach((item, i) => {
var1.forEach(list => {
list.list.forEach(val => {
val.id = i;
})
item.data = list;
})
})
console.log(var2)
I would like to have that each list.id equal the index of var2, like below, really not sure how to make this code work, please help~
var2 = [
{ claim:'claim1',ifn:'1',
data:
[{
'name':'name1',
'list':[
{id:0,a:"test1",b:'test2'},
{id:0,a:"aac",b:'test2'},
{id:0,a:"aad",b:'test2'},
]
},
{
'name':'name2',
'list':[
{id:0,a:"test1",b:'test2'},
{id:0,a:"aac",b:'test2'},
{id:0,a:"aad",b:'test2'},
]
}]
},
{ claim:'claim2',ifn:'2',
data:
[{
'name':'name1',
'list':[
{id:1,a:"test1",b:'test2'},
{id:1,a:"aac",b:'test2'},
{id:1,a:"aad",b:'test2'},
]
},
{
'name':'name2',
'list':[
{id:1,a:"test1",b:'test2'},
{id:1,a:"aac",b:'test2'},
{id:1,a:"aad",b:'test2'},
]
}]
},
{ claim:'claim3',ifn:'3',
data:[{
'name':'name1',
'list':[
{id:2,a:"test1",b:'test2'},
{id:2,a:"aac",b:'test2'},
{id:2,a:"aad",b:'test2'},
]
},
{
'name':'name2',
'list':[
{id:2,a:"test1",b:'test2'},
{id:2,a:"aac",b:'test2'},
{id:2,a:"aad",b:'test2'},
]
}]
}
]

From my understanding, you want every data value in your var2 to point to var1. The following loop will do that:
var2.forEach(item => item.data = var1);
However, because each item points to the same object, it means that if you change any data item inside var2, it will change all of them.
If you need the copies to be unique, you can make a new copy with something like this:
const getVar1 = () => [
{
'name': 'name1',
'list': [
{
id: 0,
a: "test1",
b: 'test2'
},
{
id: 0,
a: "aac",
b: 'test2'
},
{
id: 0,
a: "aad",
b: 'test2'
},
]
},
...
];
and then you can use it like so:
var2.forEach(item => item.data = getVar1())

Here you need create new copy. But desire result you can use this code -
for (var i = 0; i < var2.length; i++) {
var el = var2[i], arr = [];
for (var j = 0; j < var1.length; j++) {
var o = var1[j];
for (var k = 0; k < o.list.length; k++) {
var ob = o.list[k];
console.log(ob);
ob.id = i;
}
arr.push(o);
}
el.data = arr;
}

Related

How to get the combination of array values from nested arrays in an array of objects

I have an array of objects with the following structure:
var varientSections = [
{
type: "frame",
values: ["black", "white", "wood"]
},
{
type: "finish",
values: ["matte", "glossy"]
}
];
I want to get the combination of the array values and create a new list with it. Right now, I am able to retrieve the combination from the nested array values using the method called getCombination(varientSections). However, I do not know how to create a new list with the following structure:
var results = [
{
attributes: [
{
type: "frame",
value: "black"
},
{
type: "finish",
value: "matte"
}
]
},
{
attributes: [
{
type: "frame",
value: "black"
},
{
type: "finish",
value: "glossy"
}
]
},
{
attributes: [
{
type: "frame",
value: "white"
},
{
type: "finish",
value: "matte"
}
]
},
{
attributes: [
{
type: "frame",
value: "white"
},
{
type: "finish",
value: "glossy"
}
]
},
{
attributes: [
{
type: "frame",
value: "wood"
},
{
type: "finish",
value: "matte"
}
]
},
{
attributes: [
{
type: "frame",
value: "wood"
},
{
type: "finish",
value: "glossy"
}
]
}
];
Below is my code:
function getCombinations(arr) {
if (arr.length === 0) {
return [[]];
}
let [current, ...rest] = arr;
let combinations = getCombinations(rest);
var result = current.values.reduce(
(accumulator, currentValue) => [
...accumulator,
...combinations.map(c => [currentValue, ...c])
],
[]
);
console.log("result is ");
console.log(result);
return result;
}
let varientCombinations = getCombinations(varientSections);
console.log(varientCombinations);
let updatedVarientDetails = [];
varientSections.forEach((varientSection, index) => {
let type = varientSection.type;
varientCombinations.forEach(combination => {
let obj = [
{
type: type,
value: combination[index]
},
];
updatedVarientDetails.push(obj);
});
});
console.log(updatedVarientDetails);
You could get the cartesian product and give it later the wanted style. The names and values are taken form the handed over object.
The algorithm takes all key/value pairs and has a stric view to the values, that means if an array is found or an object, hence w && typeof w === "object", the actual part is taken an used for adding additional key/value pairs.
For example a small object with two properties
{ a: 1, b: [2, 3] }
yields
[
{ a: 1, b: 2 },
{ a: 1, b: 3 }
]
A bit more advanced object, like
{ a: 1, b: { c: { d: [2, 3], e: [4, 5] } } }
yields the same structure as given
[
{
a: 1,
b: {
c: { d: 2, e: 4 }
}
},
{
a: 1,
b: {
c: { d: 2, e: 5 }
}
},
{
a: 1,
b: {
c: { d: 3, e: 4 }
}
},
{
a: 1,
b: {
c: { d: 3, e: 5 }
}
}
]
Thant means, from any found sub object the cartesian product is taken and combined with the actual values.
const
getCartesian = object => Object.entries(object).reduce(
(r, [key, value]) => {
let temp = [];
r.forEach(s =>
(Array.isArray(value) ? value : [value]).forEach(w =>
(w && typeof w === "object" ? getCartesian(w) : [w]).forEach(x =>
temp.push({ ...s, [key]: x })
)
)
);
return temp;
},
[{}]
),
data = [{ type: "frame", value: ["black", "white", "wood"] }, { type: "finish", value: ["matte", "glossy"] }],
result = getCartesian(data)
.map(o => ({ attributes: Object.assign([], o).map(({ ...o }) => o) }));
console.log(result);
console.log(getCartesian({ a: 1, b: { c: { d: [2, 3], e: [4, 5] } } }));
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could simplify it to this:
var variantSections = [
{
type: "frame",
values: ["black", "white", "wood"]
},
{
type: "finish",
values: ["matte", "glossy"]
}
];
// iterate through each variantSection and create objects like {"type": "frame", "value": "black"}
var sections = variantSections.map(variant => {
return variant.values.map(val => ({type: variant.type, value: val}))
});
// then iterate through the two resulting arrays of objects, combining each into the attributes object you want
var results = [];
for (var i = 0; i < sections[0].length; i++) {
for (var j = 0; j < sections[1].length; j++) {
results.push({attributes: [sections[0][i], sections[1][j]]});
}
}
console.log(JSON.parse(JSON.stringify(results)));

check the difference between two arrays of objects in javascript [duplicate]

This question already has answers here:
How to get the difference between two arrays of objects in JavaScript
(22 answers)
Closed 1 year ago.
I need some help. How can I get the array of the difference on this scenario:
var b1 = [
{ id: 0, name: 'john' },
{ id: 1, name: 'mary' },
{ id: 2, name: 'pablo' },
{ id: 3, name: 'escobar' }
];
var b2 = [
{ id: 0, name: 'john' },
{ id: 1, name: 'mary' }
];
I want the array of difference:
// [{ id: 2, name: 'pablo' }, { id: 3, name: 'escobar' }]
How is the most optimized approach?
I´m trying to filter a reduced array.. something on this line:
var Bfiltered = b1.filter(function (x) {
return x.name !== b2.reduce(function (acc, document, index) {
return (document.name === x.name) ? document.name : false
},0)
});
console.log("Bfiltered", Bfiltered);
// returns { id: 0, name: 'john' }, { id: 2, name: 'pablo' }, { id: 3, name: 'escobar' } ]
Thanks,
Robot
.Filter() and .some() functions will do the trick
var b1 = [
{ id: 0, name: 'john' },
{ id: 1, name: 'mary' },
{ id: 2, name: 'pablo' },
{ id: 3, name: 'escobar' }
];
var b2 = [
{ id: 0, name: 'john' },
{ id: 1, name: 'mary' }
];
var res = b1.filter(item1 =>
!b2.some(item2 => (item2.id === item1.id && item2.name === item1.name)))
console.log(res);
You can use filter to filter/loop thru the array and some to check if id exist on array 2
var b1 = [{ id: 0, name: 'john' }, { id: 1, name: 'mary' }, { id: 2, name: 'pablo' }, { id: 3, name: 'escobar' } ];
var b2 = [{ id: 0, name: 'john' }, { id: 1, name: 'mary' }];
var result = b1.filter(o => !b2.some(v => v.id === o.id));
console.log(result);
Above example will work if array 1 is longer. If you dont know which one is longer you can use sort to arrange the array and use reduce and filter.
var b1 = [{ id: 0, name: 'john' }, { id: 1, name: 'mary' }, { id: 2, name: 'pablo' }, { id: 3, name: 'escobar' } ];
var b2 = [{ id: 0, name: 'john' }, { id: 1, name: 'mary' }];
var result = [b1, b2].sort((a,b)=> b.length - a.length)
.reduce((a,b)=>a.filter(o => !b.some(v => v.id === o.id)));
console.log(result);
Another possibility is to use a Map, allowing you to bring down the time complexity to O(max(n,m)) if dealing with a Map-result is fine for you:
function findArrayDifferences(arr1, arr2) {
const map = new Map();
const maxLength = Math.max(arr1.length, arr2.length);
for (let i = 0; i < maxLength; i++) {
if (i < arr1.length) {
const entry = arr1[i];
if (map.has(entry.id)) {
map.delete(entry.id);
} else {
map.set(entry.id, entry);
}
}
if (i < arr2.length) {
const entry = arr2[i];
if (map.has(entry.id)) {
map.delete(entry.id);
} else {
map.set(entry.id, entry);
}
}
}
return map;
}
const arr1 = [{id:0,name:'john'},{id:1,name:'mary'},{id:2,name:'pablo'},{id:3,name:'escobar'}];
const arr2 = [{id:0,name:'john'},{id:1,name:'mary'},{id:99,name:'someone else'}];
const resultAsArray = [...findArrayDifferences(arr1,arr2).values()];
console.log(resultAsArray);

deleting an element in nested array using filter() function

I have been trying to delete an element with an ID in nested array.
I am not sure how to use filter() with nested arrays.
I want to delete the {id: 111,name: "A"} object only.
Here is my code:
var array = [{
id: 1,
list: [{
id: 123,
name: "Dartanan"
}, {
id: 456,
name: "Athos"
}, {
id: 789,
name: "Porthos"
}]
}, {
id: 2,
list: [{
id: 111,
name: "A"
}, {
id: 222,
name: "B"
}]
}]
var temp = array
for (let i = 0; i < array.length; i++) {
for (let j = 0; j < array[i].list.length; j++) {
temp = temp.filter(function(item) {
return item.list[j].id !== 123
})
}
}
array = temp
You can use the function forEach and execute the function filter for every array list.
var array = [{ id: 1, list: [{ id: 123, name: "Dartanan" }, { id: 456, name: "Athos" }, { id: 789, name: "Porthos" }] }, { id: 2, list: [{ id: 111, name: "A" }, { id: 222, name: "B" }] }];
array.forEach(o => (o.list = o.list.filter(l => l.id != 111)));
console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }
To remain the data immutable, use the function map:
var array = [{ id: 1, list: [{ id: 123, name: "Dartanan" }, { id: 456, name: "Athos" }, { id: 789, name: "Porthos" }] }, { id: 2, list: [{ id: 111, name: "A" }, { id: 222, name: "B" }] }],
result = array.map(o => ({...o, list: o.list.filter(l => l.id != 111)}));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could create a new array which contains elements with filtered list property.
const result = array.map(element => (
{
...element,
list: element.list.filter(l => l.id !== 111)
}
));
You can use Object.assign if the runtime you are running this code on does not support spread operator.
Array.filter acts on elements:
var myArray = [{something: 1, list: [1,2,3]}, {something: 2, list: [3,4,5]}]
var filtered = myArray.filter(function(element) {
return element.something === 1;
// true = keep element, false = discard it
})
console.log(filtered); // logs [{something: 1, list: [1,2,3]}]
You can use it like this:
var array = [{
id: 1,
list: [{
id: 123,
name: "Dartanan"
}, {
id: 456,
name: "Athos"
}, {
id: 789,
name: "Porthos"
}]
}, {
id: 2,
list: [{
id: 111,
name: "A"
}, {
id: 222,
name: "B"
}]
}]
for (var i = 0; i < array.length; ++i) {
var element = array[i]
// Filter the list
element.list = element.list.filter(function(listItem) {
return listItem.id !== 111 && listItem.name !== 'A';
})
}
console.log(array)

using javascript filter() with a flag

I want to return arr2 but want to prompt the user whether there's changes or not by comparing it with arr. with below's approach, I got id of undefined if arr2 have any missing item.
var arr = [{
id: 1,
name: 'something'
}, {
id: 2,
name: 'something2'
}]
var arr2 = [{
id: 1,
name: 'something'
}]
var result = arr.filter(function(obj, i) {
return obj.id == arr2[i].id;
});
document.write(JSON.stringify(result))
The problem in your code is that arr[1] is undefined and you are trying to get id property of undefined. Now what you can do is, get id's in array then get index and check based on that in filter.
var arr = [{
id: 1,
name: 'something'
}, {
id: 2,
name: 'something2'
}]
var arr2 = [{
id: 1,
name: 'something'
}];
var arrIds = arr2.map(function(v) {
return v.id;
});
var result = arr.filter(function(obj) {
var i = arrIds.indexOf(obj.id);
return i > -1 &&
obj.name == arr2[i].name; // check name property here
});
document.write(JSON.stringify(result))
Loop through arr2 in a callback of the .filter to test each item of arr2.
var arr = [{
id: 1,
name: 'something'
}, {
id: 2,
name: 'something2'
}]
var arr2 = [{
id: 1,
name: 'something'
}, {
id: 5,
name: 'something'
}, {
id: 8,
name: 'something'
}];
var isValInArr = function(arr, key, val) {
for (var i = 0, len = arr.length; i < len; i++) {
if (arr[i][key] === val) {
return true;
}
}
return false;
};
var result = arr.filter(function(obj, i) {
return isValInArr(arr2, 'id', obj.id);
});
document.write(JSON.stringify(result))

How do I remove duplicate objects in an array by field in Javascript?

I have an array of objects:
[{
id: 1,
name: 'kitten'
}, {
id: 2,
name: 'kitten'
},{
id: 3,
name: 'cat
}]
How do I remove the second kitten? Sorting into an array of names doesn't work, because I can't know if I am deleting id 1 or or id 2. So, I'm not quite sure how to do this.
You can use an additional hash-map to store names found so far. When you process a next object if it's name is already in the hash-map it is a duplicate and you can remove it.
var duplicates = {};
for (var i = 0; i < array.length) {
var obj = array[i];
if (! duplicates[obj.name]) {
duplicates[obj.name] = 1;
i++;
} else {
array.splice(i, 1);
}
}
there is the lodash library.
You could use the uniq
var array = [{
id: 1,
name: 'kitten'
}, {
id: 2,
name: 'kitten'
},{
id: 3,
name: 'cat'
}];
var asd = _.uniq(array,'name');
console.log(asd);
Gives an output:
[ { id: 1, name: 'kitten' }, { id: 3, name: 'cat' } ]
as it written in the documentation "only the first occurence of each element is kept".
var arr =[{
id: 1,
name: 'kitten'
}, {
id: 2,
name: 'kitten'
},{
id: 3,
name: 'cat'
}];
var results = [];
var idsSeen = {}, idSeenValue = {};
for (var i = 0, len = arr.length, name; i < len; ++i) {
name = arr[i].name;
if (idsSeen[name] !== idSeenValue) {
results.push(arr[i]);
idsSeen[name] = idSeenValue;
}
}
console.log(results);

Categories

Resources