Hi I m trying to remove duplicates from array of object using id, but id's are null then the object should contain those null id's and remove others which are duplicate
Here is the array of objects example:
const arr = [
{
id: 6652,
value: "erger"
},
{
id: 6652,
value: "sdfs"
},
{
id: 6653,
value: "sdgdfg"
},
{
id: 6000,
value: "trgd"
},
{
id: 6667,
value: "asdf"
},
{
id: 6667,
value: "fdg"
},
{
id: 6668,
value: "dfgr"
},
{
id: null,
value: "fg"
},
{
id: null,
value: "dfgdf"
},
{
id: null,
value: "fg"
},
{
id: null,
value: "dfgdf"
}
];
Below is the finalResult
array = [{
id: 6652
value: "sdfs"
},
{
id: 6653
value: "sdgdfg"
},
{
id: 6000
value: "trgd"
},
{
id: 6667
value: "fdg"
},
{
id: 6668
value: "dfgr"
},
{
id: null
value: "fg"
},
{
id: null
value: "dfgdf"
},
{
id: null
value: "fg"
},
{
id: null
value: "dfgdf"
}
]
In the above result the 6652 and 6667 is removed as they were duplicates and but null id are kept as i don't want to remove the null id and remove other repeated values.
Below is the logic i am trying to use but it doesn't work if ids are null
array= array.filter((v,i,a)=>a.findIndex(t=>( v.id !== null && t.id === v.id ))===i)
const filterKeys = {};
const filtered = arr.reduce((acc, item) => {
if (item.id === null || !(item.id in filterKeys)) {
filterKeys[item.id] = true;
acc.push(item);
}
return acc;
}, []);
Create a separate object to keep track of object ids that have been encountered, filterKeys in this case.
Since array is an array, do a reduce to iterate over the array. If the id is nuil or not found in filterKeys, push the item to the accumulator and return it for the next iteration. Since we don't care about ids that are null, they don't have an effect and are thus not filtered out.
Use this below code I tested(working) with your array of objects :
arr.forEach(function (item) {
if (item.id == null) {
result.push(item);
}
else {
var index = result.findIndex(x => x.id == item.id);
if (index == -1)
{
result.push(item);
}
}
});
console.log(result)
You can try this out-
const array = [{ id: 6652, value: 'erger' },{ id: 6652, value: 'sdfs' },{ id: 6653, value: 'sdgdfg' },{ id: 6000, value: 'trgd' },{ id: 6667, value: 'asdf' },{ id: 6667, value: 'fdg' },{ id: 6668, value: 'dfgr' },{ id: null, value: 'fg' },{ id: null, value: 'dfgdf' },{ id: null, value: 'fg' },{ id: null, value: 'dfgdf' },];
let index = 0;
const result = Object.values(
array.reduce(
(acc, curr) =>
curr.id === null ? { ...acc, [index++]: curr } : { ...acc, [curr.id]: curr },
{}
)
);
console.log(result);
.as-console-wrapper {min-height: 100%; top: 0}
Related
I have an array and want to change name in object { id: 4, name: 'name4' } to 'name6'
const example = [
{
id: '1234',
desc: 'sample1',
items: [
{ id: 1, name: 'name1' },
{ id: 2, name: 'testItem2' }
]
},
{
id: '3456',
desc: 'sample2',
items: [
{ id: 4, name: 'name4' },
{ id: 5, name: 'testItem5' }
]
},
I try in this way but it isn't working
const name = 'name4';
const result = example?.forEach((group) =>
group.items.forEach((item) =>
if (item.name === name) {
return item.name === 'name6';
}
return null;
})
);
The for...of statement is my recommendation for readability and loop optimisation.
const example = [
{
id: '1234',
desc: 'sample1',
items: [
{ id: 1, name: 'name1' },
{ id: 2, name: 'testItem2' },
],
},
{
id: '3456',
desc: 'sample2',
items: [
{ id: 4, name: 'name4' },
{ id: 5, name: 'testItem5' },
],
},
];
const oldName = 'name4';
const newName = 'name6';
for (const group of example) {
for (const item of group.items) {
if (item.name === oldName) {
item.name === newName;
break
}
}
}
You could even go a step further and terminate the outer loop with a label if you only need to change the name in a single group.
outerLoop: for (const group of example) {
for (const item of group.items) {
if (item.name === oldName) {
item.name === newName;
break outerLoop;
}
}
}
Hope this helps.
You could either change the value by simply assigning a new value.
example[1].items[0].name = 'name6'
But you can also iterate through all items and search for the name you want to change. I created a function that goes through an array and loops over its nested items arrays searching for any given name (targetName) and replacing it with a new one (newName):
function changeName(array, targetName, newName) {
// Loop through the elements of array
array.forEach((element) => {
// Check each item: change the name if it matches the target
element.items.forEach((item) => {
if (item.name === targetName) item.name = newName;
});
});
}
// This function will check example array and change
// every name that has a value 'name4' into 'name6'
changeName(example, "name4", "name6");
forEach doesn't return any value.
Instead of return item.name === 'name6' you can simply set new value to item.name.
Why not like this?
const example = [{
id: '1234',
desc: 'sample1',
items: [{
id: 1,
name: 'name1'
},
{
id: 2,
name: 'testItem2'
}
]
},
{
id: '3456',
desc: 'sample2',
items: [{
id: 4,
name: 'name4'
},
{
id: 5,
name: 'testItem5'
}
]
},
]
example[1].items[0].name = 'name6'
console.log(example)
I have an array as:
const arr=[{
id: 9,
name: 'Patrimônios',
children: [],
},
{
id: 10,
name: 'Despesas',
children: [
{ id: 16, name: 'Manutenção' },
{ id: 17, name: 'Despesa' },
{ id: 18, name: 'Impostos' },
{ id: 19, name: 'Gráfica' },
],
},
....]
I´d like a function to delete a item by id. As we can see the item can be into 'children' or not. If the item is in the "children" I´d like to delete it from children array only.
I´d like something as:
findById(tree, nodeId) {
for (const node of tree) {
if (node.id === nodeId) return node
if (node.children && node.children.length) {
const desiredNode = this.findById(node.children, nodeId)
if (desiredNode) return desiredNode
}
}
return false
},
function deleteItemById(arr,id){
item=findById(arr,id)
if (item){
/// here How I can delete it?
}
}
How could I do that?
Here is a recursive function that matches your code's terminology to filter an object by id:
const removeObjectByIdRecursively = (list, id) => list.reduce((acc, item) => {
if (item.id === id) return acc;
if (item.children) {
return [
...acc,
{
...item,
children: removeObjectByIdRecursively(item.children, id)
}
];
}
return [
...acc,
item
];
}, []);
Super basic, untested and targeted directly at the shape of your data, but this shows how you can use Array.filter() to return a new array that doesn't contain the elements you want to remove by id.
const testArray = [
{ id: 0, value: "zero" },
{ id: 1, value: "one", children: [{ id: 3 }] },
{ id: 2, value: "two" },
{ id: 3, value: "three" },
{ id: 4, value: "four" },
];
const deleteObjectById = ({ ary, id }) => ary.filter((item) => {
const child = (item.children || []).find((c) => c.id === id);
return item.id !== id && !(!!child);
});
const filteredArray = deleteObjectById({
ary: testArray,
id: 3,
});
console.log(testArray);
console.log(filteredArray);
I am trying to merge values in 2 objects from the same array. The objects in this case are similar and the values I want to merge are arrays(Set)
var array = [
{
name: "foo1",
value: ["val1","val2"]
},
{
name: "foo1",
value: ["val2", "val3"]
},
{
name: "foo2",
value: ["val4"]
},
{
name: "foo2",
value: ["val4","val5"]
},
];
Expected Output
[
{
name: "foo1",
value: ["val1","val2", "val3"]
},{
name: "foo2",
value: ["val4","val4", "val5"]
}
]
My Code
var output = [];
array.forEach(function(item) {
var existing = output.filter(function(v, i) {
return v.name == item.name;
});
if (existing.length) {
var existingIndex = output.indexOf(existing[0]);
let newValue = new Set(output[existingIndex].value).add(item.value)
output[existingIndex].value = Array.from(newValue);
} else {
output.push(item);
}
});
Output Gotten
[ {
name: "foo1",
value: ["val1", "val2", ["val2", "val3"]]
}, {
name: "foo2",
value: ["val4", ["val4", "val5"]]
}]
How can I get the expected output (ES6 would also be preferred)
Try this
const array = [
{
"name": "foo1",
"value": [
"val1",
"val2",
"val3"
]
},
{
"name": "foo1",
"value": [
"val2",
"val3"
]
},
{
"name": "foo2",
"value": [
"val4",
"val5"
]
},
{
"name": "foo2",
"value": [
"val4",
"val5"
]
}
]
const result = []
for (const item of array) {
const existingItem = result.find(i => i.name === item.name)
if (existingItem) {
existingItem.value = [...new Set([...existingItem.value, ...item.value])]
} else {
result.push(item)
}
}
console.log(result)
Is this code solve your problem?
var array = [
{
name: "foo1",
value: ["val1","val2"]
},
{
name: "foo1",
value: ["val2", "val3"]
},
{
name: "foo2",
value: ["val4"]
},
{
name: "foo2",
value: ["val4","val5"]
},
];
var output = [];
array.forEach(function(item) {
var existing = output.filter(function(v, i) {
return v.name == item.name;
});
if (existing.length) {
var existingIndex = output.indexOf(existing[0]);
let newValue = new Set(output[existingIndex].value.concat(item.value))
output[existingIndex].value = Array.from(newValue);
} else {
output.push(item);
}
});
try
var arr = [
{
name: "foo1",
value: ["val1","val2"]
},
{
name: "foo1",
value: ["val2", "val3"]
},
{
name: "foo2",
value: ["val4"]
},
{
name: "foo2",
value: ["val4","val5"]
},
];
var arr2={}
arr.map((elem,ind)=>{
if(!arr2[elem.name]){
arr2[elem.name]=[]
}
arr2[elem.name]=[...arr2[elem.name],...elem.value]
})
arr=Object.keys(arr2);
arr.map((elem,ind)=>{
arr[ind]={name:elem,value:arr2[elem]};
})
You can do the following using reduce,
var array = [
{
name: "foo1",
value: ["val1","val2"]
},
{
name: "foo1",
value: ["val2", "val3"]
},
{
name: "foo2",
value: ["val4"]
},
{
name: "foo2",
value: ["val4","val5"]
},
];
res = array.reduce((prev, curr) => {
let index = prev.findIndex(item => item.name === curr.name);
if(index > -1) {
s = new Set([...prev[index].value, ...curr.value]);
prev[index].value = Array.from(s);
} else {
prev.push(curr);
}
return prev;
},[]);
console.log(res);
You could use reduce method with a Map as accumulator value and then use spread syntax ... on Map values to get an array of values.
var array = [{"name":"foo1","value":["val1","val2","val2","val3"]},{"name":"foo1","value":["val2","val3"]},{"name":"foo2","value":["val4","val4","val5"]},{"name":"foo2","value":["val4","val5"]}]
const map = array.reduce((r, { name, value }) => {
if (!r.has(name)) r.set(name, { name, value })
else r.get(name).value.push(...value)
r.get(name).value = [...new Set(r.get(name).value)]
return r;
}, new Map)
const result = [...map.values()]
console.log(result)
One approach is to create an unique list of keys and iterate over it. Create an array for each key and merge the values. The vanilla js way is:
Array.from(new Set(array.map(el => el.name)))
.map(name => ({
name,
value: Array.from(new Set(array.filter(el => el.name === name).flatMap(el => el.value)))
}))
Example:
const array = [
{
name: "foo1",
value: ["val1","val2"]
},
{
name: "foo1",
value: ["val2", "val3"]
},
{
name: "foo2",
value: ["val4"]
},
{
name: "foo2",
value: ["val4","val5"]
},
];
console.log(Array.from(new Set(array.map(el => el.name)))
.map(name => ({
name,
value: Array.from(new Set(array.filter(el => el.name === name).flatMap(el => el.value)))
})));
Using lodash you can reduce it to
_.uniq(array.map(el => el.name))
.map(name => ({
name,
value: _.uniq(array.filter(el => el.name === name).flatMap(el => el.value))
}))
Example:
const array = [
{
name: "foo1",
value: ["val1","val2"]
},
{
name: "foo1",
value: ["val2", "val3"]
},
{
name: "foo2",
value: ["val4"]
},
{
name: "foo2",
value: ["val4","val5"]
},
];
console.log(_.uniq(array.map(el => el.name))
.map(name => ({
name,
value: _.uniq(array.filter(el => el.name === name).flatMap(el => el.value))
})));
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.20/lodash.min.js"></script>
Find unique values of keys. Match this keys within array and return unique objects. Push this objects in an empty array. Then match other objects value with the new arrays objects value and push the unmatched values to this new array.
var arr = [
{
name: "foo1",
value: ["val1","val2"]
},
{
name: "foo1",
value: ["val2", "val3"]
},
{
name: "foo2",
value: ["val4"]
},
{
name: "foo2",
value: ["val4","val5"]
},
];
let key = [];
arr.map((val)=>key.push(val.name));
let uniquekeys = [...new Set(key)]; //unique values of keys
let newarr = [];
uniquekeys.map((uniquekey,ind)=>{
let reduceunique = arr.filter((vals)=>uniquekey == vals.name); // return matching objects as array
newarr.push(reduceunique[0]); // Push unique objects in an empty array
for(let i = 1; i<uniquekeys.length;i++){
reduceunique[i].value.map((val)=>{
let existvalue = newarr[ind].value.indexOf(val); // Match every value with the unique objects values
if(existvalue<0){
newarr[ind].value.push(val); // push the unmatched value in the array
}
});
};
});
console.log(newarr);
try to use Array.reduce and Array.filter to get the result like the following
var array = [
{
name: "foo1",
value: ["val1","val2"]
},
{
name: "foo1",
value: ["val2", "val3"]
},
{
name: "foo2",
value: ["val4"]
},
{
name: "foo2",
value: ["val4","val5"]
},
];
res = array.reduce((prev, curr) => {
let index = prev.findIndex(item => item.name === curr.name);
if(index > -1) {
prev[index].value = [...prev[index].value, ...curr.value];
prev[index].value = prev[index].value.filter((v,i) => prev[index].value.indexOf(v) === i)
} else {
prev.push(curr);
}
return prev;
},[]);
console.log(res);
This question already has answers here:
Group array items using object
(19 answers)
Closed 3 years ago.
I have an array Object which has same Id and different values. I need an output with same id and different values merged to the id.
Input:
let data = [{
id: 1,
value: 'Honda'
},
{
id: 2,
value: 'Fiat'
},
{
id: 2,
value: 'Porche'
},
{
id: 1,
value: 'Benz'
}
];
Output:
result = [{
id: 1,
value: ['Honda', 'Benz']
}, {
id: 2,
value: ['Fiat', 'Porche']
}
Hope it will helps you. But this question is duplicate
let data = [{
id: 1,
value: 'Honda'
},
{
id: 2,
value: 'Fiat'
},
{
id: 2,
value: 'Porche'
},
{
id: 1,
value: 'Benz'
}
];
var output = [];
data.forEach(function(item) {
var existing = output.filter(function(v, i) {
return v.id == item.id;
});
if (existing.length) {
var existingIndex = output.indexOf(existing[0]);
output[existingIndex].value = output[existingIndex].value.concat(item.value);
} else {
if (typeof item.value == 'string')
item.value = [item.value];
output.push(item);
}
});
console.dir(output);
const data = [{
id: 1,
value: 'Honda'
},
{
id: 2,
value: 'Fiat'
},
{
id: 2,
value: 'Porche'
},
{
id: 1,
value: 'Benz'
}
];
const expectedResult = [{
id: 1,
value: ['Honda', 'Benz']
}, {
id: 2,
value: ['Fiat', 'Porche']
}
];
const result = [];
data.forEach((e, i) => {
const indexOfExisting = result.findIndex(x => x.id === e.id);
if (indexOfExisting === -1) {
result.push({
id: e.id,
value: [e.value]
})
} else {
result[indexOfExisting].value.push(e.value);
}
});
// console.log(result)
console.log(expectedResult)
You can use Array.prototype.reduce() to achieve it.
let data = [{
id: 1,
value: 'Honda'
},
{
id: 2,
value: 'Fiat'
},
{
id: 2,
value: 'Porche'
},
{
id: 1,
value: 'Benz'
}
];
let result = data.reduce((acc, ele) => {
let filtered = acc.filter(el => el.id == ele.id)
if (filtered.length > 0) {
filtered[0]["value"].push(ele.value);
} else {
element = {};
element["id"] = ele.id;
element["value"] = []
element["value"].push(ele.value);
acc.push(element)
}
return acc;
}, [])
console.log(result)
How can we return an array of object's property values?
[
{ id: 1, category: 'A' },
{ id: 2, category: 'A' },
{ id: 3, category: 'C' },
{ id: 4, category: 'B' },
{ id: 5, category: 'A' },
]
I would like to get all the ids with category = 'A' [1, 2, 5] and using .map() include an undefined objects which i don't like and filter returns the entire object and not the id.
Using .map() output: [1, 2, undefined, undefined, 5]
using .filter() output:
[
Object {
category: 'A',
id: 1
},
Object {
category: 'A',
id: 2
},
Object {
category: 'A',
id: 5,
},
]
DEMO
One option is to use Array#filter and then Array#map:
var data = [{"id":1,"category":"A"},{"id":2,"category":"A"},{"id":3,"category":"C"},{"id":4,"category":"B"},{"id":5,"category":"A"}];
var result = data.filter(function(item) {
return item.category === 'A';
}).map(function(item) {
return item.id;
});
console.log(result);
Another option is to use Array#reduce:
var data = [{"id":1,"category":"A"},{"id":2,"category":"A"},{"id":3,"category":"C"},{"id":4,"category":"B"},{"id":5,"category":"A"}];
var result = data.reduce(function(items, item) {
item.category === 'A' && items.push(item.id);
return items;
}, []);
console.log(result);
You could use Array#reduce with a single loop.
var array = [{ id: 1, category: 'A' }, { id: 2, category: 'A' }, { id: 3, category: 'C' }, { id: 4, category: 'B' }, { id: 5, category: 'A' }],
category = 'A',
result = array.reduce(function (r, o) {
if (o.category === category) {
r.push(o.id);
}
return r;
}, []);
console.log(result);
you could combine both filter() and map()
var data = [{ id: 1, category: 'A' }, { id: 2, category: 'A' }, { id: 3, category: 'C' }, { id: 4, category: 'B' }, { id: 5, category: 'A' }]
var new_data_filter = data.filter(function(item) {
if (item.category === 'A') {
return item.id
}
}).map(function(a){return a.id})
console.log(new_data_filter)
For ES6
var new_data_filter = data.filter(item => item.category === 'A').map(a => a.id)