Transform a nested object using lodash - javascript

Input:
const a = {
"8": [{
"strategy": 123,
"id": 1,
"config": {
"global_dag_conf": {
"algo_v2_conf": {
"features_to_combine": [],
"segments": [],
"force_performance": false,
"min_bid": 0,
"max_bid": 13
}
}
}
}],
"13": [{
"strategy": 456,
"id": 2,
"config": {
"global_dag_conf": {
"algo_v2_conf": {
"ivr_measured": []
}
}
}
}]
}
Output:
{
"8": [
{
"global_dag_conf": {
"algo_v2_conf": {
"features_to_combine": [],
"segments": [],
"force_performance": false,
"min_bid": 0,
"max_bid": 13
}
},
"algo_id": 1
}
],
"13": [
{
"global_dag_conf": {
"algo_v2_conf": {
"ivr_measured": []
}
},
"algo_id": 2
}
]
}
I tried below solution which works fine but need to know if is there any better way to do this using lodash and JS.
result = _.map(_.keys(addtionalAlgos), (algoType) => {
addtionalAlgos[algoType] = _.map(addtionalAlgos[algoType], v => _.assign(v.config, { algo_id: v.id }));
return addtionalAlgos;
})[0]

Here's a solution without using lodash:
Use Object.entries() to get an array of key-value pairs
Create a new object by using reduce over the array
Use map to create a new array of objects.
Destructure each object to get id and config. Spread the config variable to remove one level of nesting
const input = {"8":[{"strategy":123,"id":1,"config":{"global_dag_conf":{"algo_v2_conf":{"features_to_combine":[],"segments":[],"force_performance":false,"min_bid":0,"max_bid":13}}}}],"13":[{"strategy":456,"id":2,"config":{"global_dag_conf":{"algo_v2_conf":{"ivr_measured":[]}}}}]}
const output =
Object.entries(input)
.reduce((r, [key, value]) => {
r[key] = value.map(({ id, config }) => ({ algo_id: id, ...config }));
return r;
}, {})
console.log(output)

Use _.mapValues() to iterate the keys, and Array.map() with object destructuring and spread syntax to reformat the object:
const data = {"8":[{"strategy":123,"id":1,"config":{"global_dag_conf":{"algo_v2_conf":{"features_to_combine":[],"segments":[],"force_performance":false,"min_bid":0,"max_bid":13}}}}],"13":[{"strategy":456,"id":2,"config":{"global_dag_conf":{"algo_v2_conf":{"ivr_measured":[]}}}}]}
const result = _.mapValues(data,
arr => arr.map(({ id: algo_id, config }) =>
({ algo_id, ...config })
))
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>

A pure Lodash solution using mapValues, map and assign methods
let data = {"8":[{"strategy":123,"id":1,"config":{"global_dag_conf":{"algo_v2_conf":{"features_to_combine":[],"segments":[],"force_performance":false,"min_bid":0,"max_bid":13}}}}],"13":[{"strategy":456,"id":2,"config":{"global_dag_conf":{"algo_v2_conf":{"ivr_measured":[]}}}}]};
let res = _.mapValues(data, arr => _.map(arr, obj => _.assign({
'algo_id': obj.id,
'global_dag_conf': obj.config.global_dag_conf
})));
console.log(res);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>

An alternative without lodash.
The function reduce allows to generate an object which will be filled using the function map which transforms the original objects to the desired structure.
const a = { "8": [{ "strategy": 123, "id": 1, "config": { "global_dag_conf": { "algo_v2_conf": { "features_to_combine": [], "segments": [], "force_performance": false, "min_bid": 0, "max_bid": 13 } } } }], "13": [{ "strategy": 456, "id": 2, "config": { "global_dag_conf": { "algo_v2_conf": { "ivr_measured": [] } } } }] };
let result = Object.entries(a).reduce((a, [key, arr]) => {
return Object.assign(a, {[key]: arr.map(({id: algo_id, config}) => ({algo_id, ...config}))});
}, Object.create(null));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

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

Loop through an object and only return certain keys together with their values

Given the following object, how can I loop through this object inorder to obtain both keys and values but only for the following keys:
"myName": "Demo"
"active": "Y"
"myCode": "123456789"
"myType": 1
let a = {
"values": {
"myName": "Demo",
"active": "Y",
"myCode": "123456789",
"myType": 1,
"myGroups": [
{
"myGroupName": "Group 1",
"myTypes": [
{
"myTypeName": "323232",
"myTypeId": "1"
}
]
},
{
"myGroupName": "Group 2",
"myTypes": [
{
"myTypeName": "523232",
"myTypeId": "2"
}
]
}
]
}
}
I have tried:
for (const [key, value] of Object.entries(a.values)) {
console.log(`${key}: ${value}`);
For}
but this will return all keys with their values.
You can use a dictionary (array) to contain the keys you want to extract the properties for, and then reduce over the values with Object.entries to produce a new object matching only those entries included in the dictionary.
let a = {
"values": {
"myName": "Demo",
"active": "Y",
"myCode": "123456789",
"myType": 1,
"myGroups": [{
"myGroupName": "Group 1",
"myTypes": [{
"myTypeName": "323232",
"myTypeId": "1"
}]
},
{
"myGroupName": "Group 2",
"myTypes": [{
"myTypeName": "523232",
"myTypeId": "2"
}]
}
]
}
}
const arr = [ 'myName', 'active', 'myCode', 'myType' ];
const out = Object.entries(a.values).reduce((acc, [key, value]) => {
if (arr.includes(key)) acc[key] = value;
return acc;
}, {});
console.log(out);
The best answer would be to set up an array of the desired keys and then iterate over that array instead of an array of the original object's entries. This is how you would achieve that:
let a = {
values: {
myName: "Demo",
active: "Y",
myCode: "123456789",
myType: 1,
myGroups: [{
myGroupName: "Group 1",
myTypes: [{
myTypeName: "323232",
myTypeId: "1"
}]
}, {
myGroupName: "Group 2",
myTypes: [{
myTypeName: "523232",
myTypeId: "2"
}]
}]
}
};
const keys = ['myName', 'active', 'myCode', 'myType'];
const cherryPick = (obj, keys) => keys.reduce((a,c) => (a[c] = obj[c], a), {});
console.log(cherryPick(a.values, keys));
The above example will work for many provided keys. If a key does not exist in the supplied object, its value will be undefined. If you want to only keep properties which have values, simply add an optional filter to the cherryPick() function, like this:
let test = {
a: 1,
b: 2
};
const keys = ['a', 'b', 'c'];
const cherryPick = (obj, keys, filter = 0) => keys.filter(key => filter ? obj[key] : 1).reduce((acc,key) => (acc[key] = obj[key], acc), {});
console.log('STORE undefined :: cherryPick(test, keys)', cherryPick(test, keys));
console.log('FILTER undefined :: cherryPick(test, keys, 1)', cherryPick(test, keys, true));
/* Ignore this */ .as-console-wrapper { min-height: 100%; }

How to filter in two deep arrays

I'm looking to filter in two deep arrays, actually my JSON:
{
"0": {
"product":[{
"uuid":"uid",
"name":"Rice"
},
{
"uuid":"uid",
"name":"Pasta"
}]
},
"1": {
"product":[{
"uuid":"uid",
"name":"Milk"
}]
}
}
I would like to get something like that when I filter with the word "ric":
{
"0": {
"product":[{
"uuid":"uid",
"name":"Rice"
}]
}
}
But I got this result:
{
"0": {
"product":[{
"uuid":"uid",
"name":"Rice"
},
{
"uuid":"uid",
"name":"Pasta"
}]
}
}
My code:
dataSort.categories = the json and
event.target.value.toLowerCase() = the specific word
dataSort.categories.filter(s => s.products.find(p => p.name.toLowerCase().includes(event.target.value.toLowerCase())));
You can achieve this with a combination of reduce and filter
var input = {
"0": {
"product":[{
"uuid":"uid",
"name":"Rice"
},
{
"uuid":"uid",
"name":"Pasta"
}]
},
"1": {
"product":[{
"uuid":"uid",
"name":"Milk"
}]
}
}
var search = "ric"
var result = Object.entries(input).reduce( (acc, [key,val]) => {
found = val.product.filter(x => x.name.toLowerCase().includes(search.toLowerCase()))
if(found.length){
acc[key] = {...val, product: found}
}
return acc
},{})
console.log(result)
There is many approach to do this, one is to map your top level array to the subArrays filtered results then filter it after:
dataSort.categories
.map(s => s.products.filter(p => p.name.toLowerCase().includes(event.target.value.toLowerCase())))
.filter(s => !!s.products.length);
You may also prefer to get a "flat" array as result because it is easier to use after :
dataSort.categories
.reduce((acc, s) => [...acc, s.products.filter(p => p.name.toLowerCase().includes(event.target.value.toLowerCase()))], []);
Please find below the code to filter out values inside the product.name and only return the value which are matching the equality condition in product array.
const json = [
{
product: [
{
uuid: "uid",
name: "Rice",
},
{
uuid: "uid",
name: "Pasta",
},
],
},
{
product: [
{
uuid: "uid",
name: "Milk",
},
],
},
];
const inputValue = "rIc";
const filteredArray = [];
json.map((s) => {
const item = s.product.find((p) =>
p.name.toLowerCase().includes(inputValue.toLowerCase())
);
item && filteredArray.push({ product: item });
});
console.dir(filteredArray);
Your dataset is an Object, not an Array and the filter is an Array method. You can use reduce by looping on the object values by Object.values then filter your products array.
const data = {
'0': {
product: [
{
uuid: 'uid',
name: 'Rice',
},
{
uuid: 'uid',
name: 'Pasta',
},
],
},
'1': {
product: [
{
uuid: 'uid',
name: 'Milk',
},
],
},
};
const keyword = 'ric';
const dataset = Object.values(data);
const results = dataset.reduce((acc, item, index) => {
const search = keyword.toLowerCase();
const product = item.product.filter(product => product.name.toLowerCase().includes(search));
if (product.length) acc[index] = { ...item, product };
return acc;
}, {});
console.log(results);

JavaScript/lodash data transformation

var original = {
"8": [{
"temp": {
"a": 1
},
"algo_id": 1
},
{
"temp": {
"a": 2
},
"algo_id": 101
}
],
"13": {
"temp": {
"temp1": [1, 2]
},
"algo_id": 2
}
};
const values = _.values(original);
const temp = _.map(values, (v) => {
if (_.isArray(v)) {
return _.mapValues(_.keyBy(v, 'algo_id'), a => _.pick(a, 'temp'));
}
});
console.log(temp);
.as-console-wrapper { top: 0; max-height: 100% !important; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
Expected:
map which has algo_id as key and temp as values.
like below and so on.
{
"1": {
"temp": {
"a": 1
}
},
"101": {
"temp": {
"a": 2
}
},
"2": {
"temp": {
"temp1": [1, 2]
}
}
}
How to add key and values which are not array in the object.?
One way to do this (not using lodash) is the following:
const transform = (original) => Object.values(original)
.flat()
.reduce((all, {algo_id, ...rest}) => ({...all, [algo_id]: rest}), {})
const original ={"13": {"algo_id": 2, "temp": {"temp1": [1, 2]}}, "8": [{"algo_id": 1, "temp": {"a": 1}}, {"algo_id": 101, "temp": {"a": 2}}]}
console.log(transform(original))
But this makes the assumption that you can use the sibling of algo_id as is. Your example seems to show further processing of it that I can't see any rule for.
If your target environments don't support flat, you can replace this:
.flat()
with this:
.reduce((a, b) => a.concat(b), [])
No need to use lodash, you can do this in plain JavaScript for this.
let original = {
"8": [{
"temp": {
"a": 1
},
"algo_id": 1
},
{
"temp": {
"a": 2
},
"algo_id": 101
}
],
"13": {
"temp": {
"temp1": [1, 2]
},
"algo_id": 2
}
};
console.log(convert(original, 'algo_id'));
function convert(data, key) {
let process = function(value, key, result) {
result[value[key]] = value;
delete result[value[key]][key]; // Remove the `algo_id` key
};
return Object.keys(data).reduce((result, k, i) => {
if (Array.isArray(data[k])) {
data[k].forEach(val => process(val, key, result));
} else {
process(data[k], key, result);
}
return result;
}, {});
}
.as-console-wrapper { top: 0; max-height: 100% !important; }
<!--
{
"1": {
"temp": {
"a": 1
}
}
}
-->
With lodash, after getting the values, flatten the mixed array of arrays and objects, use keyBy to convert back to an object with the algo_id as key, and then map the sub object to omit the algo_id property.
const { flow, partialRight: pr, values, flatten, keyBy, mapValues, omit } = _
const fn = flow(
values, // convert to a mixed array of objects and arrays
flatten, // flatten to an array of objects
pr(keyBy, 'algo_id'), // convert to object with algo_id as key
pr(mapValues, pr(omit, 'algo_id')), // remove algo_id from the sub objects
);
const original = {"8":[{"temp":{"a":1},"algo_id":1},{"temp":{"a":2},"algo_id":101}],"13":{"temp":{"temp1":[1,2]},"algo_id":2}};
const result = fn(original);
console.log(result);
.as-console-wrapper { top: 0; max-height: 100% !important; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

Es6 way to convert object key value to one single object

I want to convert all data into one object,
let d = {
"Coupon_Code": "code",
"Coupon_Name": "namie",
"Coupon_Desc": 1000,
"selectedCity": [
{
"Coupon_City_Name": "xyz"
}
],
"selectedCategory": [
{
"Coupon_Category_Name": "Shopping"
}
],
"selectedCompany": [
{
"Coupon_Company_Name": "Shopper Stop"
}
],
"selectedState": [
{
"Coupon_State_Name": "abc"
}
],
"Coupon_Date": "2222-02-22",
}
i tried some methods of Object like keys , entries but dont no what to use.
Final output should be
let d = {
Coupon_Code: "code",
Coupon_Name: "namie",
Coupon_Desc: 1000,
Coupon_City_Name: "xyz",
Coupon_Category_Name: "Shopping",
Coupon_Company_Name: "Shopper Stop",
Coupon_State_Name: "abc",
Coupon_Date: "2222-02-22",
};
what's the best and optimum way to have above result using Venila Js and Es6
Reduce the entries of the original object. If the entry's value is an array merge the 1st element, if not merge the original key and value. You can merge the properties into the object using object spread:
const data = {"Coupon_Code":"code","Coupon_Name":"namie","Coupon_Desc":1000,"selectedCity":[{"Coupon_City_Name":"xyz"}],"selectedCategory":[{"Coupon_Category_Name":"Shopping"}],"selectedCompany":[{"Coupon_Company_Name":"Shopper Stop"}],"selectedState":[{"Coupon_State_Name":"abc"}],"Coupon_Date":"2222-02-22"};
const result = Object.entries(data)
.reduce((r, [k, v]) => ({
...r,
...Array.isArray(v) ? v[0] : { [k]: v }
}), {});
console.log(result);
You can use Array.reduce and Object.entries
let d = {"Coupon_Code":"code","Coupon_Name":"namie","Coupon_Desc":1000,"selectedCity":[{"Coupon_City_Name":"xyz"}],"selectedCategory":[{"Coupon_Category_Name":"Shopping"}],"selectedCompany":[{"Coupon_Company_Name":"Shopper Stop"}],"selectedState":[{"Coupon_State_Name":"abc"}],"Coupon_Date":"2222-02-22"};
d = Object.entries(d).reduce((a,[k,v]) => {
// If the value is an array, iterate over it to merge into the resultant object
if(Array.isArray(v)) Object.assign(a, ...v)
else Object.assign(a, {[k]:v}) // if it is not an array, merge into resultant object
return a;
}, {});
console.log(d);
You could take a recursive approach.
const
fn = o => Object.assign(...Object.entries(o).map(([k, v]) => Array.isArray(v) ? Object.assign(...v.map(fn)) : { [k]: v })),
d = { Coupon_Code: "code", Coupon_Name: "namie", Coupon_Desc: 1000, selectedCity: [{ Coupon_City_Name: "xyz" }], selectedCategory: [{ Coupon_Category_Name: "Shopping" }], selectedCompany: [{ Coupon_Company_Name: "Shopper Stop" }], selectedState: [{ Coupon_State_Name: "abc" }], Coupon_Date: "2222-02-22" },
result = fn(d);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
A possible iterative solution is:
function flatten(obj) {
let r = {}
for (let [key, value] of Object.entries(obj)) {
if (Array.isArray(value)) {
Object.assign(r, value[0]);
} else {
Object.assign(r, {[key]: value});
}
}
return r;
}
Something like this:
const d = { Coupon_Code: "code", Coupon_Name: "namie", Coupon_Desc: 1000, selectedCity: [{ Coupon_City_Name: "xyz" }], selectedCategory: [{ Coupon_Category_Name: "Shopping" }], selectedCompany: [{ Coupon_Company_Name: "Shopper Stop" }], selectedState: [{ Coupon_State_Name: "abc" }], Coupon_Date: "2222-02-22" };
function toSingleObj(obj) {
var result = {};
Object.entries(obj).forEach(([key,value]) => {
if (Array.isArray(value)) {
Object.entries(value[0]).forEach(([k,v]) => {
result[k] = v;
});
} else {
result[key] = value;
}
});
return result;
}
console.log("Result: ", toSingleObj(d));

Categories

Resources