multi level groupby with function on a property - javascript

This is similar to multi level groupby ramda js, but with a twist that is giving me trouble. In addition to a two level grouping, I'd like the inner group by to be on a processed version of the property value.
Consider data like this:
const data = [
{ top: 'top1',
name: 'junk-key-a-101' },
{ top: 'top1',
name: 'junk-key-b-102' },
{ top: 'top2',
name: 'junk-key-c-103' },
{ top: 'top2',
name: 'junk-key-c-104' } ];
I can pull out the key, process it and make it unique like so:
const getZoneFromName = n => join('-', slice(1, 3, split('-', n)));
uniq(map(getZoneFromName, pluck('name', data)));
which will get me a nice list:
["key-a", "key-b", "key-c"]
I can group the list at two levels fine:
const groupByTopThenZone = pipe(
groupBy(prop("top")),
map(groupBy(prop("name")))
);
groupByTopThenZone(data);
But I cannot figure out how to combine them to get the following output:
{
top1: {
"key-a": [
{
name: "junk-key-a-101",
top: "top1"
}
],
"key-b": [
{
name: "junk-key-b-102",
top: "top1"
}
]
},
top2: {
"key-c": [
{
name: "junk-key-c-103",
top: "top2"
},
{
name: "junk-key-c-104",
top: "top2"
}
]
}
}
I'm feeling a bit silly that I can't get this. Any ideas? Here is a place to play with it.

You were very close. Just combining those functions with compose/pipe does the trick.
(Note here also a simplified version of getZoneFromName.)
const {pipe, groupBy, map, prop, slice} = R
//const getZoneFromName = n => join('-', slice(1, 3, split('-', n)));
const getZoneFromName = slice(5, -4)
const groupByTopThenZone = pipe(
groupBy(prop("top")),
map(groupBy(pipe(prop("name"), getZoneFromName)))
)
const data = [{"name": "junk-key-a-101", "top": "top1"}, {"name": "junk-key-b-102", "top": "top1"}, {"name": "junk-key-c-103", "top": "top2"}, {"name": "junk-key-c-104", "top": "top2"}]
console.log(groupByTopThenZone(data))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
Of course with this function simplified that much, it's probably easier to inline it:
const groupByTopThenZone = pipe(
groupBy(prop("top")),
map(groupBy(pipe(prop("name"), slice(5, -4)))
)
The main thing to remember is that groupBy is not necessarily tied with prop. We can group on the result of any String/Number/Symbol-generating function.

This is not using ramda, but vanilla JS.
const data = [
{ top: 'top1',
name: 'junk-key-a-101' },
{ top: 'top1',
name: 'junk-key-b-102' },
{ top: 'top2',
name: 'junk-key-c-103' },
{ top: 'top2',
name: 'junk-key-c-104' } ];
const res = data.reduce((acc, val, ind, arr) => {
const top = val.top;
// if the top does not exist in the obj, create it
if (!acc[top]) {
acc[top] = {};
}
// get the key through split. you could also use a regex here
const keyFragments = val.name.split('-');
const key = [keyFragments[1], keyFragments[2]].join('-');
// if the key obj prop does not exist yet, create the array
if (!acc[top][key]) {
acc[top][key] = [];
}
// push the value
acc[top][key].push({ name: val.name, top: val.top });
return acc;
}, {});
console.log(res);

Another way would be to construct each final object and merge them all:
You can transform this object:
{
"top": "top1",
"name": "junk-key-a-101"
}
Into this one:
{
"top1": {
"key-a": [
{
"name": "junk-key-a-101",
"top": "top1"
}
]
}
}
With these functions:
const key = slice(5, -4);
const obj = ({top, name}) => ({
[top]: {
[key(name)]: [
{top, name}
]
}
});
So now you can iterate on your data, transform each object and merge them together:
const groupByTopTenZone = reduce(useWith(mergeDeepWith(concat), [identity, obj]), {});
Full example:
const {slice, useWith, identity, reduce, mergeDeepWith, concat} = R;
const data = [
{ top: 'top1',
name: 'junk-key-a-101' },
{ top: 'top1',
name: 'junk-key-b-102' },
{ top: 'top2',
name: 'junk-key-c-103' },
{ top: 'top2',
name: 'junk-key-c-104' }
];
const key = slice(5, -4);
const obj = ({top, name}) => ({
[top]: {
[key(name)]: [
{top, name}
]
}
});
const groupByTopTenZone = reduce(useWith(mergeDeepWith(concat), [identity, obj]), {});
console.log(
groupByTopTenZone(data)
)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>

Related

Javascript: array of objects, group/restructure objects

The following object contains a list of recipients and subscriptions, I wish to create a new array with a different structure such as below.
[{"recipientId":"13251376",
"services":"3218143,15656200,3721"},{"recipientId":"13251316",
"services":"3218143"}
let serviceSubscriptions = [{"recipientId":"13251316","serviceId":"3218143"},{"recipientId":"13251376","serviceId":"3218143"},{"recipientId":"13251376","serviceId":"15656200"},{"recipientId":"13251376","serviceId":"3721"}]
let testArr = [];
serviceSubscriptions.forEach(serviceSubscriptions => {
for (const [key, value] of Object.entries(serviceSubscriptions)) {
//console.log(`${key}: ${value}`);
testArr.push(`${key}:${value}`);
}
});
console.log(testArr);
Here is a list of things I've tried - https://jsfiddle.net/v5azdysg/2/
update 30/11/22 19:08
I am trying to integrate #Mr. Polywhirl your answer with my idea, but I cannot get far as I am not skilled in this area, here is what I have so far. https://jsfiddle.net/aectk8v1/4/ What I need is to add a new key called essentially services/subscriptions with the list of ids of the subscriptions, but this should be appended to the existing list of keys and also a key which shows if subscriptions exist, true or false, on the other hand another version I need is to list all the services keys and add the value of true or false under a single key such as "subscriptions":{12345:true,123456:false}
;let recipients = [
{"id":"666777","lawfulBasis":"0","jurisdiction":"AMER","name":"David G"},
{"id":"888999","lawfulBasis":"1","jurisdiction":"ASIA","name":"Mike A"},
{"id":"444555","lawfulBasis":"2","jurisdiction":"EUR","name":"John No Sub"}
];
let serviceSubscriptions = [
{"recipientId":"666777","serviceId":"3218143"},
{"recipientId":"666777","serviceId":"8956799"},
{"recipientId":"888999","serviceId":"15656200"},
{"recipientId":"000000","serviceId":"3721"}
];
/* return subscribed */
//.map method creates new array populated with result of call
//.some performs test true|false
// ... dot notation copies all parts from 1 array to another merge/join
var result = recipients.map(Obj1 => {
return { ...Obj1,
isSubscribed:serviceSubscriptions.some(Obj2 => Obj1.id == Obj2.recipientId),
services1:serviceSubscriptions.map(Obj2 => Obj1.id == Obj2.recipientId),
services:serviceSubscriptions.map(Obj2 => Obj2.serviceId),
}
});
console.log(result)
You can reduce each item into a Map<String, Set<String>>. After you have the map, you can map the entries to objects where you join the serviceId arrays.
const serviceSubscriptions = [
{ "recipientId": "13251316", "serviceId": "3218143" },
{ "recipientId": "13251376", "serviceId": "3218143" },
{ "recipientId": "13251376", "serviceId": "15656200" },
{ "recipientId": "13251376", "serviceId": "3721" }
];
const testArr = [
...serviceSubscriptions
.reduce((acc, { recipientId, serviceId }) =>
acc.set(recipientId,
(acc.get(recipientId) ?? new Set).add(serviceId)), new Map)
.entries()
]
.map(([recipientId, serviceIds]) => ({
recipientId,
services: [...serviceIds].join(',')
}));
console.log(testArr);
.as-console-wrapper { top: 0; max-height: 100% !important; }
Here is an alternative version that uses Object and Array types instead of Map and Set types.
Note: This performs worse than the version above, because it uses spreading which mutates the accumulator and service array values. This should be avoided.
const serviceSubscriptions = [
{ "recipientId": "13251316", "serviceId": "3218143" },
{ "recipientId": "13251376", "serviceId": "3218143" },
{ "recipientId": "13251376", "serviceId": "15656200" },
{ "recipientId": "13251376", "serviceId": "3721" }
];
const testArr = Object
.entries(serviceSubscriptions
.reduce((acc, { recipientId, serviceId }) => ({
...acc,
[recipientId]: [...(acc[recipientId] ?? []), serviceId]
}), {}))
.map(([recipientId, serviceIds]) => ({
recipientId,
services: serviceIds.join(',')
}));
console.log(testArr);
.as-console-wrapper { top: 0; max-height: 100% !important; }
Efficiency
Here is the most efficient way possible. This algorithm is O(n) instead of O(2n) as seen in the preceding approaches.
const serviceSubscriptions = [
{ "recipientId": "13251316", "serviceId": "3218143" },
{ "recipientId": "13251376", "serviceId": "3218143" },
{ "recipientId": "13251376", "serviceId": "15656200" },
{ "recipientId": "13251376", "serviceId": "3721" }
];
const testArr = [], idLookup = new Map();
for (let i = 0; i < serviceSubscriptions.length; i++) {
const sub = serviceSubscriptions[i];
if (!idLookup.has(sub.recipientId)) {
idLookup.set(sub.recipientId, testArr.length);
testArr.push({
recipientId: sub.recipientId,
services: sub.serviceId
});
} else {
const index = idLookup.get(sub.recipientId);
testArr[index].services += `,${sub.serviceId}`
}
}
console.log(testArr);
.as-console-wrapper { top: 0; max-height: 100% !important; }
And here is a function version, of the code above:
const serviceSubscriptions = [
{ "recipientId": "13251316", "serviceId": "3218143" },
{ "recipientId": "13251376", "serviceId": "3218143" },
{ "recipientId": "13251376", "serviceId": "15656200" },
{ "recipientId": "13251376", "serviceId": "3721" }
];
const reducer = (arr, keyFn, valueFn, addFn, reducerFn) => {
const result = [], idLookup = new Map();
for (let i = 0; i < arr.length; i++) {
const item = arr[i], key = keyFn(item), val = valueFn(item);
if (!idLookup.has(key)) {
idLookup.set(key, result.length);
result.push(addFn(key, val));
} else {
const index = idLookup.get(key);
reducerFn(result[index], val);
}
}
return result;
};
const testArr = reducer(
serviceSubscriptions,
({ recipientId }) => recipientId,
({ serviceId }) => serviceId,
(key, val) => ({ recipientId: key, services: val }),
(existing, curr) => existing.services += `,${curr}`
);
console.log(testArr);
.as-console-wrapper { top: 0; max-height: 100% !important; }
Final update
This should work for your updated data:
const recipients = [
{ "id": "666777", "lawfulBasis": "0", "jurisdiction": "AMER", "name": "David G" },
{ "id": "888999", "lawfulBasis": "1", "jurisdiction": "ASIA", "name": "Mike A" },
{ "id": "444555", "lawfulBasis": "2", "jurisdiction": "EUR", "name": "John No Sub" }
];
const subscriptions = [
{ "recipientId": "666777", "serviceId": "3218143" },
{ "recipientId": "666777", "serviceId": "8956799" },
{ "recipientId": "888999", "serviceId": "15656200" },
{ "recipientId": "000000", "serviceId": "3721" }
];
const serviceIds = subscriptions.map(({ serviceId }) => serviceId);
const result = recipients.map(({ id, ...rest }) => ({
id,
isSubscribed: subscriptions.some(({ recipientId }) => recipientId === id),
...rest,
services: [...serviceIds],
services1: subscriptions.map(({ recipientId }) => recipientId === id)
}));
console.log(result);
.as-console-wrapper { top: 0; max-height: 100% !important; }
There are many ways to solve this, Mr. Polywhirl's answer is more elegant than the following (I haven't done the O() calc on it to determine efficiency vs this one), but a basic solution just needs to use a couple for loops.
One to get the elements and another to iterate over the array again starting from the next index to add the service ids. I just have an extra object to use as a map to check if we already handled the recipientId.
let serviceSubscriptions = [{"recipientId":"13251316","serviceId":"3218143"},{"recipientId":"13251376","serviceId":"3218143"},{"recipientId":"13251376","serviceId":"15656200"},{"recipientId":"13251376","serviceId":"3721"}]
let testArr = [];
const addedRecipients = {};
for(let i = 0; i < serviceSubscriptions.length; i++) {
// Create a new object so we don't alter the original.
const recipSub = Object.assign({}, serviceSubscriptions[i]);
// `undefined` is false in JS so we can check a map if we already handled it.
if (addedRecipients[recipSub.recipientId]) continue;
addedRecipients[recipSub.recipientId] = true;
for (let y = i + 1; y < serviceSubscriptions.length; y++) {
if (serviceSubscriptions[y].recipientId === recipSub.recipientId) {
recipSub.serviceId = recipSub.serviceId + ',' + serviceSubscriptions[y].serviceId;
}
}
testArr.push(recipSub);
}
console.log(testArr);
console.log(serviceSubscriptions);
Here's a simple and efficient version:
let result = Object.create(null)
for (let s of serviceSubscriptions) {
result[s.recipientId] = result[s.recipientId] ?? []
result[s.recipientId].push(s.serviceId)
}
for (let r in result)
result[r] = result[r].join()
Not sure why you'd want these arrays joined though.
I've worked on this script but is not 100% correct, I'd like the services ids user is subscribed to under a list also. such as the key example servicesExample2 . I've been trying to integrate the code from the answers but my lack of coding is blocking me Mr. Polywhirl, Stephen Gilboy, gog
;let recipients = [
{"id":"666777","lawfulBasis":"0","jurisdiction":"AMER","name":"David G"},
{"id":"888999","lawfulBasis":"1","jurisdiction":"ASIA","name":"Mike A"},
{"id":"444555","lawfulBasis":"2","jurisdiction":"EUR","name":"John No Sub"}
];
let serviceSubscriptions = [
{"recipientId":"666777","serviceId":"3218143"},
{"recipientId":"666777","serviceId":"8956799"},
{"recipientId":"888999","serviceId":"15656200"},
{"recipientId":"000000","serviceId":"3721"}
];
const recipientObj = recipients.map(({id,isSubscribed,...recipient}) => {
//if (isSubscribed === true) {
return {
id,
isSubscribed: serviceSubscriptions.some(( subs ) => subs.recipientId ===id),
test:'test',
services: serviceSubscriptions.map(({recipientId,serviceId}) => serviceId+':'+serviceSubscriptions.some(({serviceId}) => recipientId === id)),
servicesExample2: '3218143,3218143',
...recipient,
}
//}
});
console.log(recipientObj)
I think also my structure for key services is wrong
services: ["3218143:false", "8956799:false", "15656200:true", "3721:false"],
How can it make it the correc structure? like below
services: [{"3218143:false"}, {"8956799:false"}, {"15656200:true"},{"3721:false"}],
UPDATE, FINAL VERSION
const result = recipients.map(recipient => {
// Create an array of the recipient's subscription IDs
const subscriptionIds = serviceSubscriptions
.filter(subscription => subscription.recipientId === recipient.id)
.map(subscription => subscription.serviceId);
return {
...recipient,
isSubscribed: subscriptionIds.some(i=>i),
services: subscriptionIds,
servicesMatrix: serviceSubscriptions.map(({recipientId,serviceId}) => serviceId+':'+serviceSubscriptions.some(({serviceId}) => recipientId === recipient.id)),
};
});
console.log(result);

Modify array of the nested objects by its nested object's properties

I have the following structure in my array.
const data = [
{
name: 'Book_1',
value: {
eng: 'english_book_1',
sp: 'spanish_book_1'
}
},
{
name: 'Book_2',
value: {
eng: 'english_book_2',
sp: 'spanish_book_2'
}
}
];
And trying to get a structure like this:
[
{
eng: {
Book_1: 'english_book_1',
Book_2: 'english_book_2'
}
},
{
sp: {
Book_1: 'spanish_book_1',
Book_2: 'spanish_book_2'
}
}
];
So, the array should have language keys and nested book names with values in it.
I tried a couple of things but even close.
const modified = [];
const object = {};
data.forEach(el => {
Object.entries(el.value).forEach(([name, value]) => {
if (object['name']) {
}
modified.push(object);
});
});
```
Thanks.
You could reduce the array by taking an object for the language's objects.
const
data = [{ name: 'Book_1', value: { eng: 'english_book_1', sp: 'spanish_book_1' } }, { name: 'Book_2', value: { eng: 'english_book_2', sp: 'spanish_book_2' } }],
result = Object.values(data.reduce((r, { name, value }) => {
Object
.entries(value)
.forEach(([k, v]) => (r[k] ??= { [k]: {} })[k][name] = v);
return r;
}, {}));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

JavaScript Array attribute change

I have an array like this.
let arr = [
{
"ABBRIVATION":"ISB",
"name":"ISLAMABAD",
},
{
"ABBRIVATION":"RAW",
"name":"PINDI",
},
{
"ABBRIVATION":"SWB",
"name":"SWABI",
},
{
"ABBRIVATION":"AQ",
"name":"AQEEL",
},
]
I want to change it to like this
let me explain it a little. I want to assign the abbreviation directly to the name and the iterate through that array
let outout = [
{
"ISB":"ISLAMABAD"
},
{
"RAW":"ISLAMABAD"
},
{
"SWB":"SWABI"
},
{
"AQ":"AQEEL"
},
]
that is what I tried
let k = arr.map((item) => {
return item.ABB = item.name
})
console.log(k)
and here is the output
[ 'ISLAMABAD', 'PINDI', 'SWABI', 'AQEEL' ]
Here you go, use array map, simples
let arr = [
{
"ABBRIVATION":"ISB",
"name":"ISLAMABAD",
},
{
"ABBRIVATION":"RAW",
"name":"PINDI",
},
{
"ABBRIVATION":"SWB",
"name":"SWABI",
},
{
"ABBRIVATION":"AQ",
"name":"AQEEL",
},
]
let outout = arr.map(({ABBRIVATION, name}) => ({[ABBRIVATION]: name}));
console.log(outout);
Nothing more than a simple Array.prototype.map() needed.
let arr = [
{
ABBRIVATION: "ISB",
name: "ISLAMABAD",
},
{
ABBRIVATION: "RAW",
name: "PINDI",
},
{
ABBRIVATION: "SWB",
name: "SWABI",
},
{
ABBRIVATION: "AQ",
name: "AQEEL",
},
];
const result = arr.map(e => ({ [e.ABBRIVATION]: e.name }));
console.log(result);
map over the array of objects (map returns a new array) and assign the name to a new key defined by the abbreviation.
You code works the way it does because item.ABB is undefined, but you're also assigning item.name to it which does get returned, so you just get an array of names returned.
const arr=[{ABBRIVATION:"ISB",name:"ISLAMABAD"},{ABBRIVATION:"RAW",name:"PINDI"},{ABBRIVATION:"SWB",name:"SWABI"},{ABBRIVATION:"AQ",name:"AQEEL"}];
const out = arr.map(obj => {
return { [obj.ABBRIVATION]: obj.name };
});
console.log(out);
Hi I have seen people answer, but most of them use the map function, I provide some other solutions, hoping to expand the thinking
Use forEach function
const datas = [
{
"ABBRIVATION":"ISB",
"name":"ISLAMABAD",
},
{
"ABBRIVATION":"RAW",
"name":"PINDI",
},
{
"ABBRIVATION":"SWB",
"name":"SWABI",
},
{
"ABBRIVATION":"AQ",
"name":"AQEEL",
}
];
datas.forEach((obj, i, arr) => {
const{'ABBRIVATION':k, 'name':v} = obj;
arr[i] = {[k]:v};
});
console.log(datas);
Use flatMap function
const datas = [
{
"ABBRIVATION":"ISB",
"name":"ISLAMABAD",
},
{
"ABBRIVATION":"RAW",
"name":"PINDI",
},
{
"ABBRIVATION":"SWB",
"name":"SWABI",
},
{
"ABBRIVATION":"AQ",
"name":"AQEEL",
}
];
const result = datas.flatMap(obj => {
const {'ABBRIVATION':k, 'name':v} = obj;
return {[k]:v};
});
console.log(result);
this is how you suppose to do it.
arr.reduce((d, c)=>([...d, {[c.ABBRIVATION]: c.name}]),[])
let arr = [
{
"ABBRIVATION":"ISB",
"name":"ISLAMABAD",
},
{
"ABBRIVATION":"RAW",
"name":"PINDI",
},
{
"ABBRIVATION":"SWB",
"name":"SWABI",
},
{
"ABBRIVATION":"AQ",
"name":"AQEEL",
},
]
console.log(arr.reduce((data, current)=>([...data, {[current.ABBRIVATION]: current.name}]),[]))

Comparing two array of objects and replacing an object with another

I have a working function that appends an array of objects customData to the end of another array of objects testData. If an object with the same property name value appears in both arrays, then the testData object is removed and replaced with the customData object in the resulting array. The customData object takes on the order of the previous testData object.
This is my attempt however, I'm wondering if there is a better way of doing this which is also easy to read (es6)?
Thanks
https://codesandbox.io/s/recursing-river-bdp5k?file=/src/App.js
export default function App() {
const testData = [
{ display: "1", name: "TEST1" },
{ display: "2", name: "TEST2" }
];
const customData = [
{ display: "CUSTOM_1", name: "TEST1", custom: "YES" },
{ display: "CUSTOM_3", name: "TEST3", custom: "YES" }
];
let i = 0;
const newTestData = testData;
let newCustomData = customData;
while (i < customData.length) {
const view = customData[i];
const index = testData.findIndex(x => x.name === view.name);
if (index >= 0) {
newTestData[index] = customData[i];
newCustomData.splice(i, 1);
}
i += 1;
}
const concatData = newTestData.concat(newCustomData);
console.log(concatData)
return null;
}
Array#concat does not mutate the arrays, there's no need to assign them to new variables (which doesn't copy the arrays anyway). If you're seeking to use concise ES6 code, skip the while loop - there are numerous equivalents. Here's one example:
You don't define "better way" but I'll interpret it to mean "most optimized for performance and readability". In the below approach I use one pass to populate a map, and another pass to overwrite the map entries with customData where needed, and finally a Object.values() (technically a third pass) to produce the results. This is O(n) (no nested loops) versus your O(n^2) implementation.
const testData = [
{ display: "1", name: "TEST1" },
{ display: "2", name: "TEST2" }
];
const customData = [
{ display: "CUSTOM_1", name: "TEST1", custom: "YES" },
{ display: "CUSTOM_3", name: "TEST3", custom: "YES" }
];
let map = {};
testData.forEach(item => map[item.name] = item);
customData.forEach(item => map[item.name] = item);
const result = Object.values(map);
console.log(result);
For many cases including this one, where you have a bunch of data identified by a unique key (such as name), you really ought to be using objects to begin with. Any time you need an array, there's Object.values() and Object.keys().
Logic behind your code is correct.
This is almost the same, but without explicit loops:
const testData = [
{ display: "1", name: "TEST1" },
{ display: "2", name: "TEST2" }
];
const customData = [
{ display: "CUSTOM_1", name: "TEST1", custom: "YES" },
{ display: "CUSTOM_3", name: "TEST3", custom: "YES" }
];
Array.prototype.uniqueWith = function(comparator) {
return this.reduce((a, c, i) => {
const j = a.slice(i+1).findIndex(e => comparator(e, c));
if(j !== -1) {
a[i] = a[i+j+1];
a.splice(i+j+1, 1);
}
return a;
}, this);
}
const eqByName = (a, b) => a.name === b.name;
const result = [...testData, ...customData].uniqueWith(eqByName);
console.log(result);
Take a note that extending Array prototype may not be the best idea, so you may create separate function, which will take concatenated array as an argument.
Is this the kind of function you're looking for?
const result = App(myTestData(), myCustData());
console.log(result);
function App(testData, custData) {
// `indByName` returns index (in arr) of obj w/ matching name (or -1 if no match)
const indByName = (arr, name) =>
ind = arr.findIndex(o => o.name === name);
let custInd; // Identifier for output of `indByName`
const custDataClone = custData.slice(); // Prevents mutating `custData`
return testData.map(item => (
// Uses indByName to get index of corresponding custom item
custInd = indByName(custDataClone, item.name),
// Moves corresponding custom item into testData if appropriate
custInd > -1 ? custDataClone.splice(custInd, 1)[0] : item
// Appends remaining items from custDataClone to the new array
)).concat(custDataClone)
}
function myTestData(){
return [
{ display: "1", name: "TEST1" },
{ display: "2", name: "TEST2" }
];
}
function myCustData(){
return [
{ display: "CUSTOM_1", name: "TEST1", custom: "YES" },
{ display: "CUSTOM_3", name: "TEST3", custom: "YES" }
];
}

Push element value from array of objects to a variable

I have some data from a collection named "service" which has data like this:
let service_data = [
{
"name":"Service 1",
"price":60,
"resource_group_ids" :
["5d5e5dea99d9b75ff2f78dcd","5d5e85d329782914332368c8"]
},
{
"name":"Service 2",
"price":60,
"resource_group_ids" : ["5d5e5dea99d9b75ff2f7cfe"]
}
]
I want to push the resource_group_ids in a variable let say resource_groups. I don't want to loop resource_group_ids inside service_data.
You could use flatMap
const resource_groups = service_data.flatMap(o => o.resource_group_ids)
const service_data = [{"name":"Service 1","price":60,"resource_group_ids":["5d5e5dea99d9b75ff2f78dcd","5d5e85d329782914332368c8"]},{"name":"Service 2","price":60,"resource_group_ids":["5d5e5dea99d9b75ff2f7cfe"]}]
const resource_groups = service_data.flatMap(o => o.resource_group_ids)
console.log(resource_groups)
If flatMap is not supported, use concat and spread syntax to merge the 2D array returned by map
const resource_groups = [].concat(...service_data.map(o=> o.resource_group_ids))
You can use flatMap
const extractFlat = (arr, key) => {
return arr.flatMap(e => e[key]);
};
let service_data = [
{
"name":"Service 1",
"price":60,
"resource_group_ids" :
["5d5e5dea99d9b75ff2f78dcd","5d5e85d329782914332368c8"]
},
{
"name":"Service 2",
"price":60,
"resource_group_ids" : ["5d5e5dea99d9b75ff2f7cfe"]
}
]
const resource_group_ids = extractFlat(service_data, 'resource_group_ids');
console.log(resource_group_ids);
or reduce on older environments
const extractFlat = (arr, key) => {
return arr.reduce((acc, x) => acc.concat(x[key]), []);
};
You can achieve this with .map(), .join() and .split()
const service_data = [
{
name: 'Service 1',
price: 60,
resource_group_ids:
['5d5e5dea99d9b75ff2f78dcd', '5d5e85d329782914332368c8']
},
{
name: 'Service 2',
price: 60,
resource_group_ids: ['5d5e5dea99d9b75ff2f7cfe']
},
];
const result = service_data.map((r) => { return r.resource_group_ids;
}).join(',').split(',');
console.log(result);
Using .reduce:
let service_data = [{
"name": "Service 1",
"price": 60,
"resource_group_ids": ["5d5e5dea99d9b75ff2f78dcd", "5d5e85d329782914332368c8"]
},
{
"name": "Service 2",
"price": 60,
"resource_group_ids": ["5d5e5dea99d9b75ff2f7cfe"]
}
]
const resource_groups = service_data.reduce(function(result, item) {
result.concat(item.resource_group_ids)
}, [])
console.log(resource_groups)

Categories

Resources