How to group array - javascript

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)

Related

Create array of object with condition

I am creating array of object. I want to add object based on condition. But, It add false instead of not adding object in array.
I tried:
const flag = false;
const list = [
{ key: 'abc', label: 'abcd' },
flag && { key: 'bbb', label: 'abcd' },
{ key: 'ccc', label: 'abcd' },
flag && { key: 'ddd', label: 'abcd' },
{ key: 'eee', label: 'abcd' },
];
console.log(list);
You can check output there are false in array.
Assuming that all elements that are to be kept in the array do not have falsey values, you could simply filter them based on the value afterwards like so:
const flag = false;
const list = [
{ key: 'abc', label: 'abcd' },
flag && { key: 'bbb', label: 'abcd' },
{ key: 'ccc', label: 'abcd' },
flag && { key: 'ddd', label: 'abcd' },
{ key: 'eee', label: 'abcd' }
].filter(Boolean);
console.log("list:", list);
const flag2 = true;
const list2 = [
{ key: 'abc', label: 'abcd' },
flag2 && { key: 'bbb', label: 'abcd' },
{ key: 'ccc', label: 'abcd' },
flag2 && { key: 'ddd', label: 'abcd' },
{ key: 'eee', label: 'abcd' }
].filter(Boolean);
console.log("list2:", list2);
To do it all in a single statement, you can use the spread operator:
const list = [
{ key: 'abc', label: 'abcd' },
...(flag ? [{ key: 'bbb', label: 'abcd' }] : []),
{ key: 'ccc', label: 'abcd' },
...(flag ? [{ key: 'ddd', label: 'abcd' }] : []),
{ key: 'eee', label: 'abcd' },
];
It's pretty ugly though.

Typescript Interface Definition dynamic

I am trying to define an interface for the following data:
result =
{
"data1" : [ { "type1" : 30 }, { "type2" :40 } ],
"data1" : [ { "abc" : 40 }, { "def" 940 } ],
"data3" : []
}
here the keys and values inside result object are dynamic. Even the values inside array of objects are dynamic but it will be of format string: number or that array can be empty just as in data3.
I tried using [x:any]: any, but looks like it will remove the significance of rest of the types defined in interface as it will match eveything.
Can someone help me here?
You can define dynamic key interface as follows:
interface Result {
[key: string]: {
[childKey: string]: number;
}[];
}
Something similar you can do -->
You don't need to use an indexer (since it a bit less typesafe). You have two options :
interface EnumServiceItem {
id: int; label: string; key: any
}
interface EnumServiceItems extends Array<EnumServiceItem>{}
// Option A
var result: EnumServiceItem[] = [
{ id: 0, label: 'CId', key: 'contentId' },
{ id: 1, label: 'Modified By', key: 'modifiedBy' },
{ id: 2, label: 'Modified Date', key: 'modified' },
{ id: 3, label: 'Status', key: 'contentStatusId' },
{ id: 4, label: 'Status > Type', key: ['contentStatusId', 'contentTypeId'] },
{ id: 5, label: 'Title', key: 'title' },
{ id: 6, label: 'Type', key: 'contentTypeId' },
{ id: 7, label: 'Type > Status', key: ['contentTypeId', 'contentStatusId'] }
];
// Option B
var result: EnumServiceItems = [
{ id: 0, label: 'CId', key: 'contentId' },
{ id: 1, label: 'Modified By', key: 'modifiedBy' },
{ id: 2, label: 'Modified Date', key: 'modified' },
{ id: 3, label: 'Status', key: 'contentStatusId' },
{ id: 4, label: 'Status > Type', key: ['contentStatusId', 'contentTypeId'] },
{ id: 5, label: 'Title', key: 'title' },
{ id: 6, label: 'Type', key: 'contentTypeId' },
{ id: 7, label: 'Type > Status', key: ['contentTypeId', 'contentStatusId'] }
]
Personally I recommend Option A (simpler migration when you are using classes not interfaces).

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

get value out of really nested json array on javascript

how do I get values out of deeply nested json array.
I need to get all pairs of (nameValue and value) from below json
var json = [{
name: 'Firstgroup',
elements: [{
name: 'Field1',
elements: [{
name: 'country32',
elements: [{
nameValue: 'city1',
value: 2025
}]
}]
},
{
name: 'Field2',
elements: [{
name: 'country22',
elements: [{
nameValue: 'city2',
value: 1875
}]
},
{
name: 'country12',
elements: [{
nameValue: 'city3',
value: 1810
}]
}]
}]
},
{
name: 'Secondgroup',
elements: [{
name: 'Field1',
elements: [{
name: 'country52',
elements: [{
nameValue: 'city4',
value: 1310
},
{
nameValue: 'city5',
value: 1125
}]
}]
},
{
name: 'Field3',
elements: [{
name: 'country42',
elements: [{
nameValue: 'city6',
value: 1100
}]
}]
}]
}];
I managed to get the first pair by this below piece of code
function getDataProvider(array)
{
var dataPoint = [];
var elements = 'elements';
var name = 'nameValue';
var value = 'value';
var i, j, len;
for (j = 0; j < array.length; j++) {
i = array[j];
if (i[elements]) {
this.getDataProvider(i[elements]);
} else {
dataPoint.push({
name: i[name],
value: i[value]
});
}
}
return dataPoint;
}
how do i get all pairs out of the above json given that this json is dynamic which the depth of it is not known but it will contain pairs of (namevalue and value)
You can make a recursive function, calling itself when it has more elements and adding the values to its result whenever it comes across a result.
var getNameAndValues = function(arr) {
var nameValuePairs = [];
for (var i = 0, len = arr.length; i < len; i++) {
var item = arr[i];
if (item.value && item.nameValue) {
nameValuePairs.push(item);
}
if (item.elements) {
nameValuePairs = nameValuePairs.concat(getNameAndValues(item.elements));
}
}
return nameValuePairs;
};
var json = [{
name: 'Firstgroup',
elements: [{
name: 'Field1',
elements: [{
name: 'country32',
elements: [{
nameValue: 'city1',
value: 2025
}]
}]
},
{
name: 'Field2',
elements: [{
name: 'country22',
elements: [{
nameValue: 'city2',
value: 1875
}]
},
{
name: 'country12',
elements: [{
nameValue: 'city3',
value: 1810
}]
}]
}]
},
{
name: 'Secondgroup',
elements: [{
name: 'Field1',
elements: [{
name: 'country52',
elements: [{
nameValue: 'city4',
value: 1310
},
{
nameValue: 'city5',
value: 1125
}]
}]
},
{
name: 'Field3',
elements: [{
name: 'country42',
elements: [{
nameValue: 'city6',
value: 1100
}]
}]
}]
}];
var result = getNameAndValues(json);
var asString = "";
for (var i = 0, len = result.length; i < len; i++) {
var item = result[i];
asString += item.nameValue + ": " + item.value + "<br/>";
}
document.body.innerHTML = asString;
You could use an iterative and recursive approach for getting the wanted properties in an array.
function getKeyValue(array) {
var result = [];
array.forEach(function iter(o) {
if (o.elements) {
o.elements.forEach(iter);
return;
}
result.push({ name: o.nameValue, value: o.value });
});
return result;
}
var data = [{ name: 'Firstgroup', elements: [{ name: 'Field1', elements: [{ name: 'country32', elements: [{ nameValue: 'city1', value: 2025 }] }] }, { name: 'Field2', elements: [{ name: 'country22', elements: [{ nameValue: 'city2', value: 1875 }] }, { name: 'country12', elements: [{ nameValue: 'city3', value: 1810 }] }] }] }, { name: 'Secondgroup', elements: [{ name: 'Field1', elements: [{ name: 'country52', elements: [{ nameValue: 'city4', value: 1310 }, { nameValue: 'city5', value: 1125 }] }] }, { name: 'Field3', elements: [{ name: 'country42', elements: [{ nameValue: 'city6', value: 1100 }] }] }] }],
result = getKeyValue(data);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
A version which returns an array for every recursive call.
function getKeyValue(array) {
return array.reduce((r, o) => r.concat(
o.elements
? getKeyValue(o.elements)
: { name: o.nameValue, value: o.value }
), []);
}
var data = [{ name: 'Firstgroup', elements: [{ name: 'Field1', elements: [{ name: 'country32', elements: [{ nameValue: 'city1', value: 2025 }] }] }, { name: 'Field2', elements: [{ name: 'country22', elements: [{ nameValue: 'city2', value: 1875 }] }, { name: 'country12', elements: [{ nameValue: 'city3', value: 1810 }] }] }] }, { name: 'Secondgroup', elements: [{ name: 'Field1', elements: [{ name: 'country52', elements: [{ nameValue: 'city4', value: 1310 }, { nameValue: 'city5', value: 1125 }] }] }, { name: 'Field3', elements: [{ name: 'country42', elements: [{ nameValue: 'city6', value: 1100 }] }] }] }],
result = getKeyValue(data);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

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

Categories