Remove only parts of duplicates in array of objects [duplicate] - javascript

This question already has answers here:
How to group by and sum an array of objects? [duplicate]
(2 answers)
Sum JavaScript object propertyA values with the same object propertyB in an array of objects
(12 answers)
Closed last month.
I have an array of objects that I want to reduce.
I have this array of products in my state objArr:
]
0: {item: 'Item 1', value: 1}
1: {item: 'Item 2' value: 3}
2: {item: 'Item 3', value: 5}
3: {item: 'Item 1', value: 3}
4: {item: 'Item 2', value: 5}
]
But I want it to be:
[
0: {item: 'Item 1', value: 4}
1: {item: 'Item 2' value: 8}
2: {item: 'Item 3', value: 5}
]
I only manage to delete an entire object and not just a key value pair. Can someone help me?
This is the closest I can get:
const findDuplicates = () => {
return objArr?.reduce((arr, item) => {
const removed = arr?.filter(i => i.item !== item.item)
const dup = [...removed, item]
return dup
}, [])
}
Output:
[
0: {item: 'Item 3', value: 5}
1: {item: 'Item 1', value: 3}
2: {item: 'Item 2', value: 5}
]

As you mention, use reduce and value property to sum them up :
const groupByItem = objArr.reduce((acc, curr) => {
if (acc[curr.item]) {
acc[curr.item].value += curr.value;
} else {
acc[curr.item] = { item: curr.item, value: curr.value };
}
return acc;
}, {});
const groupedArray = Object.values(groupByItem);

Related

How to push id of parent object to child objects?

I have an array of object which has an inner array of object, I want to push the id of parent object to each child object.
a = [
{id: 'abc', stage: [{name: 'car' , value: '123'},{name: 'bus' , value: '345'},{name: 'truck' , value: '567'}],
{id: 'def', stage: [{name: 'bike' , value: '890'},{name: 'cycle' , value: '123'},{name: 'car' , value: '456'}]}
]
expected output = [
{name: 'car' , value: '123', id: 'abc'},{name: 'bus' , value: '345', 'abc'},{name: 'truck' , value: '567', 'abc'}, {name: 'bike' , value: '890', id: 'def'},{name: 'cycle' , value: '123',id: 'def',id: 'def'},{name: 'car' , value: '456', id: 'def'}
]
Im able to get the only the stage but not able to push id to each object. pls help
const getAllStages = [].concat(...map(a, el => el.stage));
console.log(getAllStages )
Use .map() again to add el.id to each element of el.stage.
You can use .flatMap() in the outer mapping to concatenate all the results into a single array.
const a = [
{id: 'abc', stage: [{name: 'car' , value: '123'},{name: 'bus' , value: '345'},{name: 'truck' , value: '567'}]},
{id: 'def', stage: [{name: 'bike' , value: '890'},{name: 'cycle' , value: '123'},{name: 'car' , value: '456'}]}
]
result = a.flatMap(({
id,
stage
}) => stage.map(s => ({
id: id,
...s
})));
console.log(result);
If you're trying to merge in id:
let remapped = a.map(e => ({ id: a.id, ...e }));
Where that converts each entry into an object inheriting the a.id value and adding on whatever else is in the object.
Here is a example and result :)
a.forEach(function(row) {
row.stage.map(function (child) {child.id = row.id})
})
result:
[{"id":"abc","stage":[{"name":"car","value":"123","id":"abc"},{"name":"bus","value":"345","id":"abc"},{"name":"truck","value":"567","id":"abc"}]},{"id":"def","stage":[{"name":"bike","value":"890","id":"def"},{"name":"cycle","value":"123","id":"def"},{"name":"car","value":"456","id":"def"}]}]
You can write like this without using libraries
let a = [
{
id: 'abc', stage:
[
{ name: 'car', value: '123' },
{ name: 'bus', value: '345' },
{ name: 'truck', value: '567' }
]
},
{
id: 'def', stage:
[
{ name: 'bike', value: '890' },
{ name: 'cycle', value: '123' },
{ name: 'car', value: '456' }
]
}
]
let output = [];
for (const element of a) {
for (const stageElement of element.stage) {
let newElement = {
name: stageElement.name,
value: stageElement.value,
id: element.id
};
output.push(newElement);
}
}
const a = [
{id: 'abc', stage: [{name: 'car' , value: '123'},{name: 'bus' , value: '345'},{name: 'truck' , value: '567'}]},
{id: 'def', stage: [{name: 'bike' , value: '890'},{name: 'cycle' , value: '123'},{name: 'car' , value: '456'}]}
]
a.forEach(item => {
const itemId = item.id;
const stages = item.stage;
stages.forEach(stage => {
stage['id'] = itemId;
})
});
console.log(a);

How to add index number to object key? [duplicate]

This question already has answers here:
Use a concatenated (dynamic) string as JavaScript object key? [duplicate]
(6 answers)
Is it possible to add dynamically named properties to JavaScript object?
(20 answers)
how to concatenate (variable + object key names) to get the object values in dot notation [duplicate]
(1 answer)
Closed 2 years ago.
I have an array of objects like this:
const data = [
{name: 'Page A', count: 4000},
{name: 'Page B', count: 3000},
{name: 'Page C', count: 2000},
];
I need to add an index number to the count property so the list would look like this:
const wantedArray = [
{name: 'Page A', count1: 4000},
{name: 'Page B', count2: 3000},
{name: 'Page C', count3: 2000},
];
I tried this but got this ts error: Operator '+' cannot be applied to types '{ name: any; count: any; }' and 'number'.ts(2365)
let wantedArray: any = []
data.map((object: any, index) => {
wantedArray.push({
name: object.name,
count+index: start.count,
});
});
What is the best solution to achieve this? Thank you.
Simply assign wantedArray to map of the data array, also use [] to assign values with dynamic key.
const data = [
{name: 'Page A', count: 4000},
{name: 'Page B', count: 3000},
{name: 'Page C', count: 2000},
];
let wantedArray = data.map((obj, index) => {
return {
name: obj.name,
[`count${index+1}`]: obj.count
}
});
console.log(wantedArray)
Use bracket notation - [key] for the dynamic key.
const data = [{
name: 'Page A',
count: 4000
},
{
name: 'Page B',
count: 3000
},
{
name: 'Page C',
count: 2000
},
];
const wantedArray = data.map((obj, index) => ({
name: obj.name,
[`count${index+1}`]: obj.count,
}));
console.log(wantedArray);
Use [variablename] to write inside a variable name.
And since the index starts at 0, we do + 1.
const data = [
{name: 'Page A', count: 4000},
{name: 'Page B', count: 3000},
{name: 'Page C', count: 2000},
];
const result = data.map((n, i) => {
return {
name: n.name,
[`count${i+1}`]: n.count,
}
});
console.log(result);
Or if you want to push it into a new array.
const data = [
{name: 'Page A', count: 4000},
{name: 'Page B', count: 3000},
{name: 'Page C', count: 2000},
];
let wantedArray = [];
data.forEach((object, index) => {
return wantedArray.push({
name: object.name,
[`count${index+1}`]: object.count,
});
});
console.log(wantedArray);

Iterate over Array of Objects with Conditions

My Array of objects looks like this:
const categories = [{
id: 1,
name: 'level 1'
}, {
id: 2,
name: 'level 2'
}, {
id: 3,
name: 'level 3'
}];
I want to dynamically iterate over this categories array and output the name property as a string, separated with commas except the first object in the array
const output = 'level 2, level 3';
categories could potentially contain several objects.
const categories = [{
id: 1,
name: 'level 1'
}, {
id: 2,
name: 'level 2'
}, {
id: 3,
name: 'level 3'
}, ..., ..., ...];
however, it is important that the first object is not outputted
const categories = [{id: 1, name: 'level 1'}];
const output = '';
This is quite trivial
const getNames = arr => arr.map(item => item.name).slice(1).join(", "); // or slice first, map later
const categories1 = [{
id: 1,
name: 'level 1'
}, {
id: 2,
name: 'level 2'
}, {
id: 3,
name: 'level 3'
}];
const categories2 = [{
id: 1,
name: 'level 1'
}];
console.log("1:", getNames(categories1))
console.log("2:", getNames(categories2))
You could exclude first element by combining the use of destructing assignment and spread operator
const categories = [
{ id: 1, name: 'level 1' },
{ id: 2, name: 'level 2' },
{ id: 3, name: 'level 3' }
]
const [first, ...rest] = categories
const res = rest.map(cat => cat.name).join(', ')
console.log(res)
const categories = [{
id: 1,
name: 'level 1'
}, {
id: 2,
name: 'level 2'
}, {
id: 3,
name: 'level 3'
}];
const output = categories.reduce((ans, v, i) => {
return i === 1 ? v.name : (ans + ',' + v.name)
});
console.log(output)
This can be done in several ways. However, using Array.prototype.map() combined with Array.prototype.join() and Array.prototype.slice() is the easiest way.
const categories = [
{ id: 1, name: 'level 1' },
{ id: 2, name: 'level 2' },
{ id: 3, name: 'level 3' }
];
categories.slice(1).map(category => category.name).join(', ');
P.S.
using slice at first will make a new array starting from index 1 (second object)
using map will fill the new array with the value of "name" properties of all the objects in the array.
Finally, using join will convert the array to a string that consists of all the values in the array separated with the value you provide between the parentheses.

Converting nested array to object, matching array index with object id

i'm currently struggling with a redux reducer.
//backend response
const response = {
data: {
results: {
222: {
items: ['id1', 'id3']
},
333: {
items: ['id2', 'id4', 'id999 (UNKNOWN)']
}
}
}
};
//currently saved in redux state
const stateItems = [
{
id: 'id1',
name: 'item ONE'
}, {
id: 'id2',
name: 'item TWO'
}, {
id: 'id3',
name: 'item THREE'
}, {
id: 'id4',
name: 'item FOUR'
}, {
id: 'id5',
name: 'item FIVE (UNUSED)'
}, {
id: 'id6',
name: 'item SIX (UNUSED)'
}
];
//converting items: ['ids'] => items: [{id: 'id', name: 'itemName'}]
const result = Object.values(response.data.results).map((keys, index, array) => {
keys.items = keys.items.map(itemId => {
return stateItems[stateItems.findIndex(x => x.id === itemId)];
});
return response.data.results;
});
//final result should be:
const expectedFinalResult = {
222: {items: [{id: 'id1', name: 'item ONE'}, {id: 'id3', name: 'item THREE'}]},
333: {items: [{id: 'id2', name: 'item TWO'}, {id: 'id4', name: 'item FOUR'}]}
};
//both should be equal:
console.log(JSON.stringify(expectedFinalResult));
console.log(JSON.stringify(result));
console.log('same result: ' + JSON.stringify(result) === JSON.stringify(expectedFinalResult));
I ran out of ideas, how to realize it. UNUSED and UNKNOWN should be filtered out as well. So that the final result in this example just be like in the const expectedFinalResult. Currently the const result return a wrong result back.
Hopefully someone have an better idea oder better approach.
Thank you
You're on the right track with Object.entries. You can use destructuring to pick out the key ('222', '333') and the value object's items array, then use that array to filter stateItems and produce the items array for each entry in the result:
const result = {};
for (const [key, {items}] of Object.entries(response.data.results)) {
result[key] = {
items: stateItems.filter(item => items.includes(item.id))
};
}
Live Example:
//backend response
const response = {
data: {
results: {
222: {
items: ['id1', 'id3']
},
333: {
items: ['id2', 'id4', 'id999 (UNKNOWN)']
}
}
}
};
//currently saved in redux state
const stateItems = [
{
id: 'id1',
name: 'item ONE'
}, {
id: 'id2',
name: 'item TWO'
}, {
id: 'id3',
name: 'item THREE'
}, {
id: 'id4',
name: 'item FOUR'
}, {
id: 'id5',
name: 'item FIVE (UNUSED)'
}, {
id: 'id6',
name: 'item SIX (UNUSED)'
}
];
const result = {};
for (const [key, {items}] of Object.entries(response.data.results)) {
result[key] = {
items: stateItems.filter(item => items.includes(item.id))
};
}
//final result should be:
const expectedFinalResult = {
222: {items: [{id: 'id1', name: 'item ONE'}, {id: 'id3', name: 'item THREE'}]},
333: {items: [{id: 'id2', name: 'item TWO'}, {id: 'id4', name: 'item FOUR'}]}
};
//both should be equal:
console.log(JSON.stringify(result, null, 4));
.as-console-wrapper {
max-height: 100% !important;
}
That makes multiple passes through stateItems. If it or response.data.results is really, really, really, really big (like hundreds of thousands), it may be worthwhile to do a Map of the stateItems by id instead:
// Create map of state items (only once each time stateItems changes):
const stateItemMap = new Map(stateItems.map(item => [item.id, item]));
// Map results (each time you get results):
const result = {};
for (const [key, {items}] of Object.entries(response.data.results)) {
result[key] = {
items: items.map(id => stateItemMap.get(id))
};
}
Live Example:
//backend response
const response = {
data: {
results: {
222: {
items: ['id1', 'id3']
},
333: {
items: ['id2', 'id4', 'id999 (UNKNOWN)']
}
}
}
};
//currently saved in redux state
const stateItems = [
{
id: 'id1',
name: 'item ONE'
}, {
id: 'id2',
name: 'item TWO'
}, {
id: 'id3',
name: 'item THREE'
}, {
id: 'id4',
name: 'item FOUR'
}, {
id: 'id5',
name: 'item FIVE (UNUSED)'
}, {
id: 'id6',
name: 'item SIX (UNUSED)'
}
];
// Create map of state items (only once each time stateItems changes):
const stateItemMap = new Map(stateItems.map(item => [item.id, item]));
// Map results (each time you get results):
const result = {};
for (const [key, {items}] of Object.entries(response.data.results)) {
result[key] = {
items: items.map(id => stateItemMap.get(id))
};
}
//final result should be:
const expectedFinalResult = {
222: {items: [{id: 'id1', name: 'item ONE'}, {id: 'id3', name: 'item THREE'}]},
333: {items: [{id: 'id2', name: 'item TWO'}, {id: 'id4', name: 'item FOUR'}]}
};
//both should be equal:
console.log(JSON.stringify(result, null, 4));
.as-console-wrapper {
max-height: 100% !important;
}
You could do it with reduce:
Object.entries(response.data.results)
.reduce((acc, [key, { items }]) => ({
...acc,
[key]: { // we can use the dynamic keys to add in our accumulated object
items: items
.map(itemId => stateItems.find(x => x.id === itemId)) // you can use find directly instead of findIndex then access
.filter(Boolean) // we skip the unneeded elements
}
}), {});

How to remove object from array if property in object do not exist

I have the following collection of data
[{
id: '1',
date: '2017-01-01',
value: 2
},
{
id: '2',
date: '2017-01-02',
value: 3
},
{
id: '3',
value: 3
},
id: '4',
date: '2017-01-02',
value: 3
}]
I want to delete any object that does not have the 'date' property. In the example above, the object with the id 3 should be deleted.
The finished object should look like this
[{
id: '1',
date: '2017-01-01',
value: 2
},
{
id: '2',
date: '2017-01-02',
value: 3
},
id: '4',
date: '2017-01-02',
value: 3
}]
I tried to find and delete a undefined value with lodash. It does not work. The object looks exactly as it is entering.
_.each(obj, (val) => {
_.remove(val, value => value['XXX-BUDAT'] === undefined);
});
How can I use lodash for this purpose?
Thanks in advance
You can use .filter(), Object.keys(), and .includes()
let input = [
{ id: '1', date: '2017-01-01', value: 2},
{ id: '2', date: '2017-01-02', value: 3},
{ id: '3', value: 3 },
{ id: '4', date: '2017-01-02', value: 3 }
]
let output = input.filter(obj => Object.keys(obj).includes("date"));
console.log(output);
You can filter the array based on that property like this:
const initial = [{
id: '1',
date: '2017-01-01',
value: 2
},
{
id: '2',
date: '2017-01-02',
value: 3
},
{
id: '3',
value: 3
}, { // this left curly brace was missing!, check that out
id: '4',
date: '2017-01-02',
value: 3
}
];
const finalR = initial.filter((obj) => obj.hasOwnProperty('date') && !!obj.date);
console.log(finalR);
You can use Array#filter and Object#hasOwnProperty to do so:
var newArray = oldArray.filter(function(obj) {
return obj.hasOwnProperty("date");
});
Which can be shortened out using an arrow function:
var newArray = oldArray.filter(obj => obj.hasOwnProperty("date"));
Lodash solution:
var newArray = _.filter(oldArray, obj => _.has(obj, "date"));
Example:
var oldArray = [{id: '1', date: '2017-01-01', value: 2 }, { id: '2', date: '2017-01-02', value: 3 }, { id: '3', value: 3 }, {id: '4', date: '2017-01-02', value: 3}];
var newArray = oldArray.filter(obj => obj.hasOwnProperty("date"));
console.log(newArray);
You can use Array.prototype.filter. In addition, you can use ES6 object assignment destructiring to make it concise:
var data=[{id:'1',date:'2017-01-01',value:2},{id:'2',date:'2017-01-02',value:3},{id:'3',value:3},{id:'4',date:'2017-01-02',value:3}];
var result = data.filter(({date}) => date);
console.log(result)
First of all your array of object is not valid, fix it by wrapping the last object element with preceding curly brace {. See Array.prototype.filter() and Object.prototype.hasOwnProperty() that'll check your current object item has the date key or not? if it has then it'll return that object other wise that item will not return.
var array_of_object = [{
id: '1',
date: '2017-01-01',
value: 2
},
{
id: '2',
date: '2017-01-02',
value: 3
},
{
id: '3',
value: 3
},
{ //missing brace here
id: '4',
date: '2017-01-02',
value: 3
}
];
function filterByValue(item) {
return item.hasOwnProperty('date');
}
var arrByID = array_of_object.filter(filterByValue);
console.log(arrByID);
This is a native javascript solution:
var arr = [
{id: '1', date: '2017-01-01', value: 2},
{id: '2', date: '2017-01-02', value: 3},
{id: '3', value: 3},
{id: '4', date: '2017-01-02', value: 3}
]
for(var i = 0; i < arr.length; i++) {
if(!arr[i].hasOwnProperty("date")) {
arr.splice(i,1);
}
}
console.log(arr);

Categories

Resources