What is an alternative way to update an array of objects? - javascript

I have a array of objects. I want to update an object using id.
I am able to do using the map function. Is there an alternative way or more efficient way to update the array?
Here is my code:
https://stackblitz.com/edit/js-xgfwdw?file=index.js
var id = 3
var obj = {
name: "test"
}
let arr = [{
name: "dd",
id: 1
}, {
name: "dzxcd",
id: 3
}, {
name: "nav",
id: 5
}, {
name: "hhh",
id: 4
}]
function getUpdated(obj, id) {
var item = [...arr];
const t = item.map((i) => {
if(i.id==id){
return {
...obj,
id
}
}else {
return i;
}
})
return t
}
console.log(getUpdated(obj,id))
The expected output is correct but I want to achieve the same functionality using an alternative way.
[{
name: "dd",
id: 1
}, {
name: "test",
id: 3
}, {
name: "nav",
id: 5
}, {
name: "hhh",
id: 4
}]

you are in the correct way, basically the bad thing that you are doing is creating new arrays [...arr], when map already gives you a new array.
other things to use, may be the ternary operator and return directly the result of the map function
check here the improvedGetUpdate:
var id = 3;
var obj = {
name: "test"
};
let arr = [{
name: "dd",
id: 1
}, {
name: "dzxcd",
id: 3
}, {
name: "nav",
id: 5
}, {
name: "hhh",
id: 4
}]
function getUpdated(obj, id) {
var item = [...arr];
const t = item.map((i) => {
if (i.id == id) {
return {
...obj,
id
}
} else {
return i;
}
})
return t
}
improvedGetUpdate = (obj, id) => arr.map(i => {
return i.id !== id ? i : {
...obj,
id
}
})
console.log(getUpdated(obj, id))
console.log(improvedGetUpdate(obj, id))

var id = 3
var obj = {
name: "test"
}
let arr = [{
name: "dd",
id: 1
}, {
name: "dzxcd",
id: 3
}, {
name: "nav",
id: 5
}, {
name: "hhh",
id: 4
}]
const result = arr.map((el) => el.id === id ? {...obj, id} : el)
console.log(result);

Use splice method which can be used to update the array too:
var obj = {
id: 3,
name: "test"
}
let arr = [{
name: "dd",
id: 1
}, {
name: "dzxcd",
id: 3
}, {
name: "nav",
id: 5
}, {
name: "hhh",
id: 4
}]
arr.splice(arr.findIndex(({id}) => id === obj.id), 0, obj);
console.log(arr);

#quirimmo suggested short code.
I suggest fast code.
var id = 3;
var obj = {
id: 3,
name: "test"
}
let arr = [{
name: "dd",
id: 1
}, {
name: "dzxcd",
id: 3
}, {
name: "nav",
id: 5
}, {
name: "hhh",
id: 4
}]
var arr2 = [...arr];
console.time('⏱');
arr.splice(arr.findIndex(({id}) => id === obj.id), 0, obj);
console.timeEnd('⏱');
console.time('⏱');
for (let item of arr2) {
if (item.id === id) {
item.name = obj.name;
break;
}
}
console.timeEnd('⏱');
console.log(arr2);

Related

Removing not matching obj from old array and replace matching obj from new array with old matching obj

I cant figure out how to do this...
const arr1 = [{ name: 'peter' }, { name: 'sam', id: 1 }, { name: 'mark' }];
const arr2 = [{ name: 'sam' }, { name: 't' }, { name: 'george' }];
Desired outcome:
const arr2 = [{ name: 'sam', id: 1 }, { name: 't' }, { name: 'george' }];
If you want the previous item I would do this:
const arr1 = [{
name: 'peter'
}, {
name: 'sam',
id: 1
}, {
name: 'mark'
}];
const arr2 = [{
name: 'sam'
}, {
name: 't'
}, {
name: 'george'
}];
const result = arr2.map(item => {
const previousItem = arr1.find(i => i.name === item.name)
if (previousItem) {
return previousItem
}
return item
})
console.log(result);
However, if you want to combine the old and new data, I would recommend spreading the data together, like so:
const arr1 = [{
name: 'peter'
}, {
name: 'sam',
id: 1
}, {
name: 'mark'
}];
const arr2 = [{
name: 'sam'
}, {
name: 't'
}, {
name: 'george'
}];
const result = arr2.map(item => {
const previousItem = arr1.find(i => i.name === item.name)
if (previousItem) {
return {
...previousItem,
...item
}
}
return item
})
console.log(result);
Both allude to the same result here, but you would get different results if arr2's "Sam" object had an additional key "age" on it...
In this example, the second snippet would keep the "age" key because the spread (...) operation combines the two objects together.
You can try this.
const arr1 = [{ name: 'peter' }, { name: 'sam', id: 1 }, { name: 'mark' }];
const arr2 = [{ name: 'sam' }, { name: 't' }, { name: 'george' }];
const result = [];
const res1 = arr2.map((item, i) => {
let index = arr1.findIndex((x) => x.name === item.name);
if ( index > -1 )
result.push(arr1[index]);
else
result.push(item);
})
console.log(result);

Filter out array using another array of objects

I am having two arrays
const selected = [];
const current = [
{ id: 1, name: "abc" },
{ id: 2, name: "def" }
];
const result = []
I need to compare these two arrays and the result should only have the single entry instead of duplicates. In the above example result should have the following output.
Also items in the selected should be taken into consideration and should be in the beginning of the result
result = [
{ id: 1, name: "abc" },
{ id: 2, name: "def" }
];
Also when the input is following
const selected = [ {id:5, name: "xyz" }];
const current = [
{ id: 1, name: "abc" },
{ id: 2, name: "def" }
];
result = [[
{ id: 5, name: "xyz" },
{ id: 1, name: "abc" },
{ id: 2, name: "def" }
];
Also when the input is following
const selected = [ {id:1, name: "abc" }, {id:4, name: "lmn" }];
const current = [
{ id: 1, name: "abc" },
{ id: 2, name: "def" }
];
result = [[
{ id: 1, name: "abc" },
{ id: 4, name: "lmn" }
{ id: 2, name: "def" }
];
Note the comparison should be made using name field
Code that I tried
const res = [...(selected || [])].filter((s) =>
current.find((c) => s.name === c.name)
);
Sandbox: https://codesandbox.io/s/nervous-shannon-j1vn5k?file=/src/index.js:115-206
You could get all items and filter the array by checking the name with a Set.
const
filterBy = (key, s = new Set) => o => !s.has(o[key]) && s.add(o[key]),
selected = [{ id: 1, name: "abc" }, { id: 1, name: "lmn" }],
current = [{ id: 1, name: "abc" }, { id: 2, name: "def" }],
result = [...selected, ...current].filter(filterBy('name'));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Loop through selected, and if there is no object in current with a name that matches the name of the object in the current iteration push it into current.
const selected=[{id:1,name:"abc"},{id:6,name:"def"},{id:4,name:"lmn"}];
const current=[{id:1,name:"abc"},{id:2,name:"def"}];
for (const sel of selected) {
const found = current.find(cur => cur.name === sel.name);
if (!found) current.push(sel);
}
console.log(current);
This is a good use for .reduce, avoids multiple loops/finds and doesn't need filtering with side-effects.
const selected = [ {id:1, name: "abc" }, {id:4, name: "lmn" }];
const current = [
{ id: 1, name: "abc" },
{ id: 2, name: "def" }
];
const result = Object.values(
[...selected, ...current].reduce((obj, item) => {
obj[item.name] = obj[item.name] || item;
return obj;
}, {})
)
console.log(result);

Nesting then grouping objects into arrays

I'm attempting to convert an array that I get in this format:
data = [
{ name: 'Buttons/Large/Primary', id: '1:23' },
{ name: 'Buttons/Large/Secondary', id: '1:24' },
{ name: 'Buttons/Medium/Primary', id: '1:25' },
{ name: 'Buttons/Medium/Secondary', id: '1:26' },
{ name: 'Forms/Text', id: '2:1' },
{ name: 'Forms/Checkbox', id: '2:2' },
];
to an array in this format:
data = [
{
name: "Buttons",
id: '1:23',
components: [{
name: "Large",
id: '1:23',
components: [{
name: "Primary",
id: '1:23'
}, {
name: "Secondary",
id: '1:24'
}]
},{
name: "Medium",
id: '1:25',
components: [{
name: "Primary",
id: '1:25'
}, {
name: "Secondary",
id: '1:26'
}]
}]
}, {
name: "Forms",
id: '2:1',
components: [{
name: "Text",
id: '2:1'
},{
name: "Checkbox",
id: '2:2'
}]
}
];
My approach was to create arrays from each object in the original dataset by splitting the name property at '/', then nest them inside each other. This is what I have so far, which nests each item in the original array, but lacks grouping them together like my target format shows. Suggestions?
function nestItems(obj, path, value) {
let component = {};
let temp = component;
for (let i = 0; i < path.length; i++) {
let component = temp;
component.name = path[i];
component.id = value;
if (path.length - 1 === i) {
} else {
component.components = {};
temp = component.components;
}
}
obj.push(component)
}
let obj = [];
for (let i = 0; i < data.length; i++) {
let path = data[i].name.split('/');
nestItems(obj, path, data[i].id);
}
console.log(obj)
I agree with your approach for splitting with /.
Here's my approach for using reduce to create a map and generating the final array:
const data = [
{ name: 'Buttons/Large/Primary', id: '1:23' },
{ name: 'Buttons/Large/Secondary', id: '1:24' },
{ name: 'Buttons/Medium/Primary', id: '1:25' },
{ name: 'Buttons/Medium/Secondary', id: '1:26' },
{ name: 'Forms/Text', id: '2:1' },
{ name: 'Forms/Checkbox', id: '2:2' },
];
const map = data.reduce((acc, curr) => {
const { id } = curr;
const [parent, sub, subSub] = curr.name.split('/');
if (acc[parent]) {
if (acc[parent][sub]) {
acc[parent][sub][subSub] = { id };
} else {
acc[parent][sub] = { id };
if (subSub) {
acc[parent][sub][subSub] = { id };
}
}
} else {
acc[parent] = { id };
if (sub && subSub) {
acc[parent][sub] = {
id,
[subSub]: { id }
};
} else if (sub) {
acc[parent][sub] = { id };
};
}
return acc;
}, {});
const result = Object.keys(map).map(parentName => {
const { id: parentId, ...subs } = map[parentName];
const parentObj = { name: parentName, id: parentId };
parentObj.components = Object.keys(subs).map(subName => {
const { id: subId, ...subSubs } = subs[subName];
const subObj = { name: subName, id: subId };
if (Object.keys(subSubs).length) {
subObj.components = Object.keys(subSubs).map(subSubName => ({ name: subSubName, id: subSubs[subSubName].id }));
}
return subObj;
});
return parentObj;
});
console.log(result);

Return array of objects (from array of objects)

I have the following data and I want to return an array (of objects) of years that are distinct.
I tried the following function but I'm getting an array within an array.
const data = [{
id: 1,
name: "test1",
years: [{
id: 1,
name: "year1"
}, {
id: 2,
name: "year2"
}]
},
{
id: 2,
name: "test2",
years: [{
id: 1,
name: "year1"
}]
},
]
let years = data.map((s) => {
return s.years
})
let distinctYears = Array.from(new Set(years.map(c => c.id))).map(id => {
return {
id: id,
name: years.find(c => c.id === id).name,
}
})
console.log(distinctYears);
desired outcome:
[
{id: 1, name: "year1"},
{id: 2, name: "year2"}
]
Since s.years() is an array, and data.map() returns an array of the results, years is necessarily an array of arrays.
Instead of using .map(), use .reduce() to concatenate them.
const data = [{
id: 1,
name: "test1",
years: [{
id: 1,
name: "year1"
}, {
id: 2,
name: "year2"
}]
},
{
id: 2,
name: "test2",
years: [{
id: 1,
name: "year1"
}]
},
];
const years = data.reduce((a, {
years
}) => a.concat(years), []);
let distinctYears = Array.from(new Set(years.map(c => c.id))).map(id => {
return {
id: id,
name: years.find(c => c.id === id).name,
}
});
console.log(distinctYears);
There's so many ways you can go about doing this. Here's one, it's not a one-liner but its broken down to parts to help us understand whats going on.
Your dataset:
let data =
[
{
id: 1,
name: "test1",
years: [{id: 1, name: "year1"}, {id: 2, name: "year2"} ]
},
{
id: 2,
name: "test2",
years: [{id: 1, name: "year1"} ]
},
]
Use .flatMap() to create a one-level array with all items:
let allItems = data.flatMap((item) => {
return item.years.map((year) => {
return year
})
})
Getting distinct items:
let distinct = []
allItems.forEach((item) => {
let matchingItem = distinct.find((match) => match.id == item.id && match.name == item.name)
if(!matchingItem){
distinct.push(item)
}
})
In Practice:
let data = [{
id: 1,
name: "test1",
years: [{
id: 1,
name: "year1"
}, {
id: 2,
name: "year2"
}]
},
{
id: 2,
name: "test2",
years: [{
id: 1,
name: "year1"
}]
},
]
let allItems = data.flatMap((item) => {
return item.years.map((year) => {
return year
})
})
let distinct = []
allItems.forEach((item) => {
let matchingItem = distinct.find((match) => match.id == item.id && match.name == item.name)
if (!matchingItem) {
distinct.push(item)
}
})
console.log(distinct)

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

Categories

Resources