Javascript array of objects merge based on the object property [duplicate] - javascript

This question already has answers here:
Group array items using object
(19 answers)
Closed 2 years ago.
I have an array below.
var array = [
{ category: 'Input', field: 0, value: '17' },
{ category: 'Input', field: 0, value: '5' },
{ category: 'Input', field: 0, value: '8' },
{ category: 'Input', field: 5, value: '1' },
{ category: 'Input', field: 5, value: '4' },
{ category: 'Input', field: 0, value: '1' }
];
I want to convert the array-like below -- merge the objects based on the field value, if the value is same and get the result like below
[
{ category: 'Input', field: 0, value: ['17', '5', '8', '1'] },
{ category: 'Input', field: 5, value: ['1', '4'] }
];

var array = [
{ category: 'Input', field: 0, value: '17' },
{ category: 'Input', field: 0, value: '5' },
{ category: 'Input', field: 0, value: '8' },
{ category: 'Input', field: 5, value: '1' },
{ category: 'Input', field: 5, value: '4' },
{ category: 'Input', field: 0, value: '1' }
];
const obj = array.reduce((val, cur) => {
if (val[cur.field]) {
val[cur.field].push(cur.value);
} else {
val[cur.field] = [cur.value];
}
return val;
}, {});
const res = Object.keys(obj).map(key => ({
category: 'Input',
field: parseInt(key),
value: obj[key]
}));
console.log(res);

Related

Find a nested object inside an arrary of objects based on the string

I've an array of objects in which I need to find the object which has the same value as that of the string.
I've tried this and it works.
But, is there a way to optimize it without using map?
Code:
const arr = [{
label: 'A',
options: [{
label: 'abc',
value: 'abc'
},
{
label: 'bcd',
value: 'bcd'
}
]
},
{
label: 'B',
options: [{
label: 'cde',
value: 'cde'
},
{
label: 'def',
value: 'def'
}
]
},
{
label: 'C',
options: [{
label: 'efg',
value: 'efg'
},
{
label: 'fgh',
value: 'fgh'
}
]
}
];
const str = 'cde';
const result = arr.map(obj => obj.options.find(item => item.value === str)).find(val => val !== undefined);
console.log('result', result);
Yes, you don't need or want map followed by find. Just a loop:
let result;
for (const obj of arr) {
result = obj.options.find(({value}) => value === str);
if (result) {
break;
}
}
Live Example:
const arr = [{
label: 'A',
options: [{
label: 'abc',
value: 'abc'
},
{
label: 'bcd',
value: 'bcd'
}
]
},
{
label: 'B',
options: [{
label: 'cde',
value: 'cde'
},
{
label: 'def',
value: 'def'
}
]
},
{
label: 'C',
options: [{
label: 'efg',
value: 'efg'
},
{
label: 'fgh',
value: 'fgh'
}
]
}
];
const str = 'cde';
let result;
for (const obj of arr) {
result = obj.options.find(({value}) => value === str);
if (result) {
break;
}
}
console.log('result', result);
You could take Array#flatMap with an empty array as default value.
The result is an array with matching result.
const
arr = [{ label: 'A', options: [{ label: 'abc', value: 'abc' }, { label: 'bcd', value: 'bcd' }] }, { label: 'B', options: [{ label: 'cde', value: 'cde' }, { label: 'def', value: 'def' } ] }, { label: 'C', options: [{ label: 'efg', value: 'efg' }, { label: 'fgh', value: 'fgh' }] }];
str = 'cde';
result = arr.flatMap(obj => obj.options.find(item => item.value === str) || []);
console.log('result', result);
you don't need to use find inside the map which is O(nk);
You can fetch all the options then flat the array to find the required object.
const arr = [{
label: 'A',
options: [{
label: 'abc',
value: 'abc'
},
{
label: 'bcd',
value: 'bcd'
}
]
},
{
label: 'B',
options: [{
label: 'cde',
value: 'cde'
},
{
label: 'def',
value: 'def'
}
]
},
{
label: 'C',
options: [{
label: 'efg',
value: 'efg'
},
{
label: 'fgh',
value: 'fgh'
}
]
}
];
const str = 'cde';
const result = arr.map(({options}) => options).flat().find(({value}) => value === str)
console.log('result', result);
Depending of your needs, you can do this:
const arr = [{ label: 'A', options: [{ label: 'abc', value: 'abc' }, { label: 'bcd', value: 'bcd' }] }, { label: 'B', options: [{ label: 'cde', value: 'cde' }, { label: 'def', value: 'def' } ] }, { label: 'C', options: [{ label: 'efg', value: 'efg' }, { label: 'fgh', value: 'fgh' }] }];
const re1 = /"value":"cde"/
const testStr = JSON.stringify(arr);
console.log(""+testStr)
console.log(re1.test(testStr)) // exists
const re2 = /"label":"(\w)+","value":"cde"/g
console.log(testStr.match(re2)) // label
find in the underscore library will avoid using map in this scenario:
var myObj = _.find(arr, (obj) => {
return _.find(obj.options, (elt) => elt.value === str);
});

Javascript - Assign object item with values from another object

I have an object with few items and I want to update the values of one property options from another object.
Object 1 :
structure = [
{
id: 'name',
label: 'Name',
filterType: 'text',
filterOn: 'contains'
},
{
id: 'address',
label: 'Address',
filterType: 'text',
filterOn: 'contains'
},
{
id: 'phone',
label: 'Phone',
filterType: 'select',
filterOn: 'contains',
options: [{ label: 'abc', value: 'abc' },
{ label: 'xyz', value: 'xyz' },
{ label: 'mno', value: 'mno' }]
}
];
if the id is phone then I want to get the values from the object 2 phoneList and assign it to the options instead of hard coding it.
options: [{ label: 'abc', value: 'abc' },
{ label: 'xyz', value: 'xyz' },
{ label: 'mno', value: 'mno' }]
}
];
object 2 is
this.props.phoneList = [{name: 'aaa', age: 11},{name : 'bbb' , age : 12}, and so on
]
label and values will be this.props.phoneList[i].name
how to loop over this and get the latest values from the other object
First use filter to identify the object with id phone. Then use map to transform this.probs.phoneList in the desired format and assign to options.
structure.filter (x => x.id == 'phone')[0].options = this.probs.phoneList.map (x => ({label: x.name, value: x.name}));

How to group array

I am trying to group similar objects with the same label.
At the moment, this is the the JSON I receive.
const sizes = [{
id: [{
value: '2496',
label: 'XS'
}, {
value: '2499',
label: 'S'
}],
type: 'First Size'
}, {
id: [{
value: '2863',
label: 34
}, {
value: '2866',
label: 36
}],
type: 'Shoe Sizes'
}, {
id: [{
value: '3561',
label: 'XS'
}, {
value: '3563',
label: 'S'
}, {
value: '3565',
label: 'L'
}, , {
value: '3567',
label: 'XL'
}]
}, {
id: [{
value: '3523',
label: 34
}, {
value: '2866',
label: 36
}],
type: 'Shoe Sizes'
}]
The result I am trying to achieve is
const sizes = [{
id: [{
value: '2496,3561',
label: 'XS'
}, {
value: '2499,3563',
label: 'S'
}],
type: 'First Size'
}, {
id: [{
value: '2863,3523',
label: 34
}, {
value: '2866',
label: 36
}],
type: 'Shoe Sizes'
}, {
id: [{
value: '3565',
label: 'L'
}, , {
value: '3567',
label: 'XL'
}]
}, {
id: [{
value: '2866',
label: 37
}],
type: 'Shoe Sizes'
}]
I have tried to achieve this with underscore, but I am only able to group it by just one label, and I need to group it by any kind of label, whether it be XS or 36.
I have tried with reduce below, it is close but I just need to remove the brackets around the value, and turn the value into a string.
EX: value: '2493, 2343'
var group_to_values = sizes.reduce(function (obj, item) {
obj[item.label] = obj[item.label] || [];
obj[item.label].push(item.value);
return obj;
}, {});
var groups = Object.keys(group_to_values).map(function (key) {
return {label: key, value: group_to_values[key]};
});
You could take a hash table for same labels and iterate the outer array and the inner array. If a label is not found, it generates a new entry for the result set.
var sizes = [{ id: [{ value: '2496', label: 'XS' }, { value: '2499', label: 'S' }], type: 'First Size' }, { id: [{ value: '2863', label: 34 }, { value: '2866', label: 36 }], type: 'Shoe Sizes' }, { id: [{ value: '3561', label: 'XS' }, { value: '3563', label: 'S' }, { value: '3565', label: 'L' }, { value: '3567', label: 'XL' }] }, { id: [{ value: '3523', label: 34 }, { value: '2866', label: 36 }], type: 'Shoe Sizes' }],
labels = Object.create(null),
joined = sizes.reduce((r, a) => {
var temp;
a.id.forEach(o => {
if (labels[o.label]) {
labels[o.label].value += ',' + o.value;
return;
}
if (!temp) {
temp = Object.assign({}, a, { id: [] });
r.push(temp);
}
temp.id.push(labels[o.label] = o);
});
return r;
}, []);
console.log(joined);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Here you are, the code below would output Array called result, which is data set you desired, the loop is clear so I think it won't be an issue for you to go through it:
const sizes = [{
id: [{
value: '2496',
label: 'XS'
}, {
value: '2499',
label: 'S'
}],
type: 'First Size'
}, {
id: [{
value: '2863',
label: 34
}, {
value: '2866',
label: 36
}],
type: 'Shoe Sizes'
}, {
id: [{
value: '3561',
label: 'XS'
}, {
value: '3563',
label: 'S'
}, {
value: '3565',
label: 'L'
}, {
value: '3567',
label: 'XL'
}]
}, {
id: [{
value: '3523',
label: 34
}, {
value: '2866',
label: 36
}],
type: 'Shoe Sizes'
}]
var groupedSizes = {};
for (var current, i=0;i < sizes.length ;i++){
for (var j=0;j < sizes[i]['id'].length;j++) {
current = sizes[i]['id'][j]
if (groupedSizes[current['label']] !== undefined) {
groupedSizes[current['label']].push(current['value'])
} else {
groupedSizes[current['label']] = [current['value']]
}
}
}
var result = []
for (var key in groupedSizes) {
result.push({'id': groupedSizes[key].join(','), 'label': key})
}
console.log(result)

How to return non-duplicate values of array of object

var newarray=
[ { value: 'Large', name: 'Size' },
{ value: 'Red', name: 'Color' },
{ value: 'Cotton', name: 'Material' },
{ value: 'Affinity', name: 'Collection' },
{ value: 'Pine Montage', name: 'Style' },
{ value: 'Large', name: 'Size' },
{ value: 'Red', name: 'Color' },
{ value: 'Jute', name: 'Material' },
{ value: 'Affinity', name: 'Collection' },
{ value: 'Pine Montage', name: 'Style' },
{ value: 'Large', name: 'Size' },
{ value: 'Green', name: 'Color' },
{ value: 'Jute', name: 'Material' },
{ value: 'Affinity', name: 'Collection' },
{ value: 'Pine Montage', name: 'Style' } ];
Here is my array i need to find unique array of object with non-repeated values in an array ,Please help
I suggest to iterate over the array and filter the items with a look up if the item is stored in a hash map.
var array = [{ value: 'Large', name: 'Size' }, { value: 'Red', name: 'Color' }, { value: 'Cotton', name: 'Material' }, { value: 'Affinity', name: 'Collection' }, { value: 'Pine Montage', name: 'Style' }, { value: 'Large', name: 'Size' }, { value: 'Red', name: 'Color' }, { value: 'Jute', name: 'Material' }, { value: 'Affinity', name: 'Collection' }, { value: 'Pine Montage', name: 'Style' }, { value: 'Large', name: 'Size' }, { value: 'Green', name: 'Color' }, { value: 'Jute', name: 'Material' }, { value: 'Affinity', name: 'Collection' }, { value: 'Pine Montage', name: 'Style' }],
unique = function (a) {
var o = {};
return a.filter(function (b) {
var k = b.name + '|' + b.value;
if (!(k in o)) {
o[k] = true;
return true;
}
});
}(array);
document.write('<pre>' + JSON.stringify(unique, 0, 4) + '</pre>');
You can use Set for getting unique values
var uniq = Array.from(new Set(newarray.map(function(a) {
return JSON.stringify(a);
}))).map(function(a) {
return JSON.parse(a)
});
console.log(uniq); // will print your unique values

How can I filter an array of objects based on the value of a field and the remap the objects?

I have the following object:
options.getOrderBy = function (type) {
var OrderBy = [
{ type: 'x', id: 0, label: 'xx1', key: 'yy1' },
{ type: 'x', id: 1, label: 'xx2', key: [1,2] },
{ type: 'x', id: 9, label: 'xx2', key: ['a','b'] },
{ type: 'y', id: 0, label: 'xx44', key: 'yya' },
{ type: 'y', id: 1, label: 'xx45', key: 'yyb' },
{ type: 'y', id: 2, label: 'xx46', key: 'yyc' },
];
return OrderBy;
};
What I need is that when the function is called with a type of ('x') then I want it to return something like:
[
{ id: 0, label: 'xx1', key: [1.2] },
{ id: 1, label: 'xx2', key: 'yy2' },
{ id: 9, label: 'xx2', key: ['a','b'] }
]
Can someone explain to me how I can filter an array based on the value of the type field and then just return an array of objects containing id, label and key?
Note that I have _lodash and I would like to use that if it makes it easier. Also my solution would be for browsers greater than IE9
options.getOrderBy = function (type) {
var OrderBy = [
{ type: 'x', id: 0, label: 'xx1', key: 'yy1' },
{ type: 'x', id: 1, label: 'xx2', key: 'yy2' },
{ type: 'y', id: 0, label: 'xx44', key: 'yya' },
{ type: 'y', id: 1, label: 'xx45', key: 'yyb' },
{ type: 'y', id: 2, label: 'xx46', key: 'yyc' },
];
return OrderBy.filter(function(e) {
return e.type === type;
}).map(function(e) {
delete e.type;
return e;
});
};
If you could change the OrderBy structure to an object, it will be much simpler:
options.getOrderBy = function (type) {
var OrderBy = {
x:[
{ id: 0, label: 'xx1', key: 'yy1' },
{ id: 1, label: 'xx2', key: 'yy2' }
],
y:[
{ id: 0, label: 'xx44', key: 'yya' },
{ id: 1, label: 'xx45', key: 'yyb' },
{ id: 2, label: 'xx46', key: 'yyc' }
]
};
return OrderBy[type];
};
My solution exploits Lodash's map and omit functions. See it here
var filter = function(collection, filterKey) {
return _.map(collection, function(elem) {
return _.omit(elem, filterKey);
})
}
Use it as:
var filtered = filter(OrderBy, 'type');
EDIT: taking into consideration also the value for filterKey
var filter = function(collection, filterKey, filterValue) {
return _.compact(_.map(collection, function(elem) {
if(elem[filterKey] === filterValue)
return _.omit(elem, filterKey);
}))
}
Use it as:
var filtered = filter(OrderBy, 'type', 'x');
SECOND EDIT: clearer version
var filterV2 = function(collection, filter) {
return _(collection)
.map(function (elem) { if(elem[filter.key] == filter.value) return _.omit(elem, filter.key) })
.compact()
.value()
}
Use it as:
var filtered = filterV2(OrderBy, { key: 'type', value: 'x' });
You can filter the order options like this:
var newOrderBy = [];
for(var i = 0, l = OrderBy.length; i < l; i++) {
if(OrderBy[i].type == type) {
newOrderBy.push({
id: OrderBy[i].id,
label: OrderBy[i].label,
key: OrderBy[i].key
});
}
}
Using underscore.js _.filter():-
options.getOrderBy = function (type) {
var OrderBy = [
{ type: 'x', id: 0, label: 'xx1', key: 'yy1' },
{ type: 'x', id: 1, label: 'xx2', key: [1,2] },
{ type: 'x', id: 9, label: 'xx2', key: ['a','b'] },
{ type: 'y', id: 0, label: 'xx44', key: 'yya' },
{ type: 'y', id: 1, label: 'xx45', key: 'yyb' },
{ type: 'y', id: 2, label: 'xx46', key: 'yyc' },
];
var filteredOrderBy = _.filter(OrderBy, function (order) {
if (order.type === type) {
return true;
} else return false;
});
return filteredOrderBy ;
};

Categories