JS Removing duplicates from Multidimensional array - javascript

I want to reduce the object to one when the label is the same, and sum its value, however, needs to avoid the object with both same values of label and value, here is the example:
let arr = [
{
label: "▲",
value: 5
},
{
label: "▲",
value: 10
},
{
label: "■",
value: 13
},
{
label: "●",
value: 4
},
{
label: "■",
value: 6
},
{
label: "■",
value: 6
},
]
let expectedResult = [
{
label: "▲",
value: 15
},
{
label: "■",
value: 19
},
{
label: "●",
value: 4
},
]
I tried to use let newArr = [...new Set(arr)], but it returned the same array.

You can make use of Array.reduce and Object.values and achieve the expected output.
let arr = [{label:"▲",value:5},{label:"▲",value:10},{label:"■",value:13},{label:"●",value:4},{label:"■",value:6},{label:"■",value:6},]
const getReducedData = (data) => Object.values(data.reduce((acc, obj) => {
if(acc[obj.label]) {
acc[obj.label].value += obj.value;
} else {
acc[obj.label] = { ...obj }
}
return acc;
}, {}));
console.log(getReducedData(arr));
.as-console-wrapper {
max-height: 100% !important;
}

Related

How to chain map and filter methods for a complex array of objects in Javascript?

I have an array as following:
var arr = [
{
subArray1:[
{
subArray2:[
{
value: 1
},
{
value: 0
}
]
},
{
subArray2:[
{
value: 1
},
{
value: 0
}
]
}
]
}
];
I want to filter out all objects inside the subArray2 that contains value 1 and return the whole array.
The expected output is as follows:
newArr= [
{
subArray1:[
{
subArray2:[
{
value: 1
}
]
},
{
subArray2:[
{
value: 1
}
]
}
]
}
]
I am unable to chain the map and filter methods in such a way that I get the above desired output.
Please help me to achieve that.
You'll need to map each arr item, and each arr.subArray1 item, and then filter subArray2:
var arr = [
{
subArray1:[
{
subArray2:[
{
value: 1
},
{
value: 0
}
]
},
{
subArray2:[
{
value: 1
},
{
value: 0
}
]
}
]
}
];
console.log(
arr.map(({...el}) => {
el.subArray1 = el.subArray1.map(({...el1}) => {
el1.subArray2 = el1.subArray2.filter(({value}) => value !== 0);
return el1;
});
return el;
})
)
Assuming there are only those nested arrays, you can use the function reduce along with the function filter.
const arr = [ { subArray1:[ { subArray2:[ { value: 1 }, { value: 0 } ] }, { subArray2:[ { value: 1 }, { value: 0 } ] } ] }],
result = arr.reduce((a, {subArray1}) => {
a.push({
subArray1: subArray1.reduce((a, {subArray2}) => {
a.push({subArray2: subArray2.filter(({value}) => value === 1)});
return a;
}, [])
});
return a;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

How to filter complex array whose one property value is the same and the other property value is mas? [duplicate]

This question already has answers here:
removing duplicate objects in an array, keeping ones with maximum property value
(4 answers)
JS: Filter array of objects by max value per category
(8 answers)
Closed 1 year ago.
As title, purpose is to get array with no duplicated name and value is max.
var data=[{name:'A',value:3},{name:'B',value:5},{name:'A',value:7},{name:'B',value:1},{name:'B',value:12},{name:'A',value:4}];
expected output:
var newData=[];
newData=[{name:'A',value:7},{name:'B',value:12}];
Thanks in advance
1. solution using forEach, Math.max
var data = [
{ name: "A", value: 3 },
{ name: "B", value: 5 },
{ name: "A", value: 7 },
{ name: "B", value: 1 },
{ name: "B", value: 12 },
{ name: "A", value: 4 },
];
const dict = {};
data.forEach(({ name, value }) => {
dict[name] = Math.max(value, dict[name] ?? Number.MIN_VALUE);
});
const result = Object.entries(dict).map((o) => {
const [name, value] = o;
return { name, value };
});
console.log(result);
2. Using simple forEach and if condition.
var data = [{
name: "A",
value: 3
},
{
name: "B",
value: 5
},
{
name: "A",
value: 7
},
{
name: "B",
value: 1
},
{
name: "B",
value: 12
},
{
name: "A",
value: 4
},
];
const dict = {};
data.forEach(({ name, value }) => {
if (dict[name]) {
if (dict[name] < value) dict[name] = value;
} else {
dict[name] = value;
}
});
const result = Object.entries(dict).map((o) => {
const [name, value] = o;
return { name, value };
});
console.log(result);

Comparing array elements against the rest of the array

The question might be a bit vague, but I'll explain the result I'm expecting to get with an example.
Say I have the following array made out of objects with the following shape:
[
{
id: 1,
value: 10
},
{
id: 2,
value: 100
},
{
id: 3,
value: 10
},
{
id: 4,
value: 10
},
{
id: 5,
value: 1000
},
]
This array might contain hundrends, maybe thousands of entries, but for simplicity, I'll keep it small.
What I'm trying to achieve is compare the value property of every object with the other value properties and assign a new property duplicate with a boolean value to that specific object.
Given the example above, I would expect to receive an array with the following members:
[
{
id: 1,
value: 10,
duplicate: true
},
{
id: 2,
value: 100
},
{
id: 3,
value: 10,
duplicate: true
},
{
id: 4,
value: 10,
duplicate: true
},
{
id: 5,
value: 1000
},
]
Whats the most optimal way I could implement this behavior ?
Thank you.
I'd do a single pass through the array remembering the first seen entry with a given value in a Map, marking that first entry (and any others) as duplicates if it's present, like this:
const map = new Map();
for (const entry of array) {
const previous = map.get(entry.value);
if (previous) {
previous.duplicate = entry.duplicate = true;
} else {
map.set(entry.value, entry);
}
}
Live Example:
const array = [
{
id: 1,
value: 10
},
{
id: 2,
value: 100
},
{
id: 3,
value: 10
},
{
id: 4,
value: 10
},
{
id: 5,
value: 1000
},
];
const map = new Map();
for (const entry of array) {
const previous = map.get(entry.value);
if (previous) {
previous.duplicate = entry.duplicate = true;
} else {
map.set(entry.value, entry);
}
}
console.log(array);
You can do this by first determining which are the duplicates, and then setting the 'duplicate' attribute.
counts = items.reduce((counter, item) => {
if (counter[item.value] != null) {
counter[item.value] += 1;
} else {
counter[item.value] = 1;
}
return counter;
}, {});
After this, you can go over your items, and if the count is >=2, set the 'duplicate' attribute.
items.forEach((item) => {
if (counter[item.value] > 1) {
item['duplicate'] = true;
}
});
You can use Array.map and Array.filter for that.
const input = [
{ id: 1, value: 10 },
{ id: 2, value: 100 },
{ id: 3, value: 10 },
{ id: 4, value: 10 },
{ id: 5, value: 1000 }
]
const output = input.map(entry => {
if (input.filter(x => x.value === entry.value).length > 1) {
return {
duplicate: true,
...entry
}
}
return entry
})
console.log(output)
I would create a map with value as the key, and a list of ids as the values, than after iterating over the whole map and creating the new mapping, unpack it back tothe desired form, and add duplicated for keys with more than one value.
I think this will help you. arr is your array.
arr.forEach(e=> {
const dublicatedDataLenth = arr.filter(a => a.value == e.value).length;
if(dublicatedDataLenth > 1){
e.dublicate = true;
}
})
It should be what you are looking for.
A copy from myself with a single loop and an object for storing seen values.
This approach returns a new array and does not mutate the given data.
var data = [{ id: 1, value: 10 }, { id: 2, value: 100 }, { id: 3, value: 10 }, { id: 4, value: 10 }, { id: 5, value: 1000 }],
result = data.map((seen => ({ ...o }) => {
if (o.value in seen) {
o.duplicate = true;
if (seen[o.value]) {
seen[o.value].duplicate = true;
seen[o.value] = false;
}
} else seen[o.value] = o;
return o;
})({}));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

How to merge 3 javascript object with modified value

I have 3 objects like
[
const arr = [
{name:'ABC', value:123},
{name:'ABC', value:456},
{name:'ABC',value:789},
{name:'DEF',value:9999},
name:'DEF', value:0000}
]
i want output like
updatedArr = [
{name:'ABC', value:123, value1:456, value2:789}
{name:'DEF', value:9999, value1:0000}
]
any kind of links regarding this will be also helpful.
You could use reduce method to create an object and then Object.values to get an array of values.
const arr = [{name:'ABC', value:123},{name:'ABC', value:456},{name:'ABC',value:789},{name:'DEF',value:9999},{name:'DEF', value:0000}]
const res = arr.reduce((r, e) => {
if(!r[e.name]) r[e.name] = {...e}
else {
let {name, ...rest} = r[e.name];
r[e.name][`value${Object.keys(rest).length}`] = e.value
}
return r;
}, {});
console.log(Object.values(res))
const arr = [{
name: 'ABC',
value: 123
},
{
name: 'ABC',
value: 456
},
{
name: 'ABC',
value: 789
},
{
name: 'DEF',
value: 9999
},
{
name: 'DEF',
value: 0000
}
]
const res = Object.values(arr.reduce((acc, item) => {
if (!acc[item.name]) {
acc[item.name] = item;
} else {
acc[item.name]['value' + (Object.keys(acc[item.name]).length - 1)] = item.value;
}
return acc;
}, {}));
console.log(res)
use object assignation:
Object.assign(ob1,ob2);

summarize values of objects with same attribute name

I have an array filled with objects. The following example shows the structure of the objects.
let array = [
{
data: [{name:'a', value:20}, {name:'b', value:10}, {name:'c', value:5}]
},
{
data: [{name:'d', value:20}, {name:'a', value:10}, {name:'e', value:40}]
},
{
data: [{name:'b', value:30}, {name:'a', value:5}]
}
];
I'm trying to iterate through all the data values and summarize all the identical letters and sum up there values in a new array. So the new array should look like this:
let array = [{name:'a', value:35}, {name:'b', value:40}, {name:'c', value:5}, {name:'d', value:20}, {name:'e', value:40}];
This is my current approach but I don't get it to work.
let prevData = '';
let summarizedArray = [];
for(let i = 0; i < array.length; i++) {
for(let j = 0; j < array[i].data.length; j++) {
if(prevData === array[i].data[j].name) {
let summarized = {
name: array[i].data[j].name;
value: prevData.value + array[i].data[j].value;
}
summarizedArray.push(summarized);
}
prevData = array[i].data[j];
}
}
// Edited Example:
let array = [
{
data: [{name:'a', value1:20, value2:90, value3:'foo'},
{name:'b', value1:30, value2:20, value3:'boo'}]
},
data: [{name:'c', value1:5, value2:10, value3:'goo'},
{name:'a', value1:30, value2:20, value3:'foo'}]
},
{
];
The values should be bundled by same names. The values of Value1 and Value2 should be added up and Value3 is always the same for each name.
So the result should look like this:
let result = [{name:'a', value1:50, value2:110, value3:'foo'},
{name:'b', value1:30, value2:20, value3:'boo'},
{name:'c', value1:5, value2:10, value3:'goo'}
];
You could take a Map and collect all values. Later get an array of object of the collected values.
let array = [{ data: [{ name: 'a', value: 20 }, { name: 'b', value: 10 }, { name: 'c', value: 5 }] }, { data: [{ name: 'd', value: 20 }, { name: 'a', value: 10 }, { name: 'd', value: 40 }] }, { data: [{ name: 'b', value: 30 }, { name: 'a', value: 5 }] }],
result = Array.from(
array.reduce(
(m, { data }) => data.reduce(
(n, { name, value }) => n.set(name, (n.get(name) || 0) + value),
m
),
new Map
),
([name, value]) => ({ name, value })
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
For a more convoluted object, you could take single properties to add, after a check for the type.
var array = [{ data: [{ name: 'a', value1: 20, value2: 90, value3: 'foo' }, { name: 'b', value1: 30, value2: 20, value3: 'boo' }] }, { data: [{ name: 'c', value1: 5, value2: 10, value3: 'goo' }, { name: 'a', value1: 30, value2: 20, value3: 'foo' }] }],
result = Array.from(
array.reduce(
(m, { data }) => {
data.forEach(o => {
var temp = m.get(o.name);
if (!temp) {
m.set(o.name, temp = {});
}
Object.entries(o).forEach(([k, v]) => {
if (k === 'name') return;
if (typeof v === 'number') {
temp[k] = (temp[k] || 0) + v;
} else {
temp[k] = v;
}
});
});
return m;
},
new Map
),
([name, value]) => Object.assign({ name }, value)
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Categories