Reconstruct nested object in Javascript - javascript

I have such object in Javascript and I need to reconstruct it like below :
let data = {
"10001": {
'brand': 'jeep',
'model': 'cherokee',
'price': 27335,
},
'10002': {
'brand': 'jeep',
'model': 'compas',
'price': 23775,
},
'32402': {
'brand': 'dodge',
'model': 'challenger',
'price': 29590,
}
};
like this :
let data_sorted = {
"jeep": {
10001: {
'brand': 'jeep',
'model': 'cherokee',
'price': 27335,
}, 10002: {
'brand': 'jeep',
'model': 'compas',
'price': 23775,
}
},
"dodge": {
32402: {
'brand': 'dodge',
'model': 'challenger',
'price': 29590,
}
}
};
Tried Object.assign but it merges duplicate keys .
Note brand name "jeep" is duplicate. I think it can be done using spread operator (...) three dots

You need some to buil new objects for the second level.
let data = { 10001: { brand: 'jeep', model: 'cherokee', price: 27335 }, 10002: { brand: 'jeep', model: 'compas', price: 23775 }, 32402: { brand: 'dodge', model: 'challenger', price: 29590 } },
result = Object
.entries(data)
.reduce(
(r, [k, v]) => ({ ...r, [v.brand]: { ...(r[v.brand] || {}), [k]: v } }),
{}
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Create the result object with the brands as keys, and with new objects as values. Then iterate the data to populate those new objects based on the brand:
let data = {"10001": {'brand': 'jeep','model': 'cherokee','price': 27335,},'10002': {'brand': 'jeep','model': 'compas','price': 23775,},'32402': {'brand': 'dodge','model': 'challenger','price': 29590,}};
let result = Object.fromEntries(Object.values(data).map(({brand}) => [brand, {}]));
Object.entries(data).forEach(([key, val]) => result[val.brand][key] = val);
console.log(result);

Related

Lodash - Merge object from another array with same key as sub object to main array

const _ = require('lodash');
const parentDetails = [
{
'name': '5003',
'id': '1'
},
{
'name': '5000',
'id': '2'
}
];
const childrenDetails = [
{
'cid': '11',
'Reference': '5003'
},
{
'cid': '22',
'Reference': '5000'
}
];
Desired Output using lodash library: Extract matching reference from the second array with the name of the first array and append the matching child detail as an object to the first array as shown below. The result should not mutate the original array.
result = [
{
'name': '5003',
'id': '1',
'childrenDetail' : {
'cid': '11',
'Reference': '5003'
}
},
{
'name': '5000',
'id': '2',
'childrenDetail' : {
'cid': '22',
'Reference': '5000'
}
}
];
Here is an example using _.find()
const result = parentDetails.map(elm => {
const childrenDetail = _.find(childrenDetails, elm2 => elm2.Reference === elm.name);
if (childrenDetail) return ({...elm, childrenDetail});
});
console.log(result);
You can also replace array.map() with _.map().

Sort big array into smaller by value in objects

I have large array, which looks like this:
let arr = [{
'name': '1',
'val': '12'
},{
'name': '4',
'val': '52'
},
{
'name': '11',
'val': '15'
},
{
'name': '4',
'val': '33'
},
...]
I want find all objects with same name values and push them into separated arrays .
P.S. I don't know possible name values in array.
You can easily group by name to get what you need. Below is a quite general function to group any array of objects to a Map, by specified property. Then simply make it an array and you're done
function group(arr, propertyToGroupBy) {
return arr.reduce(function(a, b) {
return a.set(b[propertyToGroupBy], (a.get(b[propertyToGroupBy]) || []).concat(b));
}, new Map);
}
const map = group(arr, 'name');
console.log(Array.from(map));
<script>
let arr = [{
'name': '1',
'val': '12'
}, {
'name': '4',
'val': '52'
},
{
'name': '11',
'val': '15'
},
{
'name': '4',
'val': '33'
}
];
</script>
You can group your array based on name in an object accumulator. Then using Object.values() you can get all the values.
let arr = [{ 'name': '1', 'val': '12' },{ 'name': '4', 'val': '52' }, { 'name': '11', 'val': '15' }, { 'name': '4', 'val': '33' }],
result = Object.values(arr.reduce((r,o) => {
r[o.name] = r[o.name] || [];
r[o.name].push(o);
return r;
},{}));
console.log(result);
let arr=[{'name':'1','val':'12'},{'name':'4','val':'52'},{'name':'11','val':'15'},{'name':'4','val':'33'}];
let groups = arr.reduce((obj, el) => ({...obj, [el.name]: [...obj[el.name] || [], el] }), {});
console.log(groups);
Group with reduce and map out the output to be an array:
let arr = [{'name': '1','val': '12'},{'name': '4','val': '52'}, {'name': '11','val': '15'},{'name': '4','val': '33'}];
// group object by same name
const dataObj = arr.reduce((all, {name, val}) => {
if (!all.hasOwnProperty(name)) all[name] = [];
all[name].push({name, val});
return all;
}, {});
// map out the result into an array
const result = Object.keys(dataObj).map(k => (dataObj[k]));
console.log(result);

Javascript merge two objects based on key

I have some objects in the shape of below.
[{
product: 'ABC',
productId: 'AB123',
batch: 'BA1',
price: '12'
}, {
product: 'ABC',
productId: 'AB123',
batch: 'BA2',
price: '15'
}, {
product: 'XYZ',
productId: 'AB124',
batch: 'XY1',
price: '124'
}]
I want to merge objects into one single object in the array if key pair (product, and productId) are mathced, in the below format.
[{
product: 'ABC',
productId: 'AB123',
batch: ['BA1', 'BA2'],
price: ['12', '15']
}, {
product: 'XYZ',
productId: 'AB124',
batch: 'XY1',
price: '124'
}]
How can I do it in lodash or in pure javascript.
This proposal does not alter the given data.
It creates new objects, first with just single data, later if more data should be grouped, it uses an array for batch and price.
var data = [{ product: 'ABC', productId: 'AB123', batch: 'BA1', price: '12' }, { product: 'ABC', productId: 'AB123', batch: 'BA2', price: '15' }, { product: 'XYZ', productId: 'AB124', batch: 'XY1', price: '124'}],
merged = [];
data.forEach(function (a) {
if (!this[a.productId]) {
this[a.productId] = { product: a.product, productId: a.productId, batch: a.batch, price: a.price };
merged.push(this[a.productId]);
return;
}
if (!Array.isArray(this[a.productId].batch)) {
this[a.productId].batch = [this[a.productId].batch];
}
if (!Array.isArray(this[a.productId].price)) {
this[a.productId].price = [this[a.productId].price];
}
this[a.productId].batch.push(a.batch);
this[a.productId].price.push(a.price);
}, Object.create(null));
console.log(merged);
You can make use of _.uniqWith to loop over the collection and get rid of duplicates. Apart from that, uniqWith grants you access to the objects themselves so you can tamper them as you like.
In this case, when a duplicate is found, I add its batch and price to the array of the original object, getting the desired result.
var arr = [{
product: 'ABC',
productId: 'AB123',
batch: 'BA1',
price: '12'
}, {
product: 'ABC',
productId: 'AB123',
batch: 'BA2',
price: '15'
}, {
product: 'XYZ',
productId: 'AB124',
batch: 'XY1',
price: '124'
}];
function addToArray(val1, val2) {
return _.isArray(val1) ? val1.concat(val2) : [val1].concat(val2);
}
function modifyObjs(a, b) {
b.batch = addToArray(b.batch, a.batch);
b.price = addToArray(b.price, a.price);
return true;
}
function predicateAndModifier(a, b) {
return a.product === b.product && a.productId === b.productId && modifyObjs(a, b);
}
console.log(_.uniqWith(arr, predicateAndModifier));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.min.js"></script>
Lodash 4.17.2
_.reduce(data, function(result, item) {
var added = _.find(result, {
product: item.product,
productId: item.productId
});
if (_.isObject(added)) {
//!! better to merge with new object and add result to array again to avoid mutable
added = _.mergeWith(added, item, function(addedVal, itemVal, key) {
if (key === 'product' || key === 'productId') {
return addedVal;
}
return _.concat(addedVal, itemVal);
});
return result;
}
return _.concat(result, item);
}, []);
You can merge similar objects in the array using a lodash's chain with _.transform() and _.mergeWith():
function mergeSimilar(arr, arrayProps) {
// transform the array into a map object
return _(arr).transform(function(result, item) {
// create a temp id that includes the product and productId
var id = item.product + item.productId;
// merge the existing item with a new item
result[id] = _.mergeWith(result[id] || {}, item, function(objValue, srcValue, key) {
// if a value exists, and it's one of the request keys, concat them into a new array
if (!_.isUndefined(objValue) && _.includes(arrayProps, key)) {
return [].concat(objValue, srcValue);
}
});
}, {})
.values() // get the values from the map object
.value();
}
var arr = [{
product: 'ABC',
productId: 'AB123',
batch: 'BA1',
price: '12'
}, {
product: 'ABC',
productId: 'AB123',
batch: 'BA2',
price: '15'
}, {
product: 'XYZ',
productId: 'AB124',
batch: 'XY1',
price: '124'
}];
var result = mergeSimilar(arr, ['batch', 'price']);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.min.js"></script>
Does it have to be readable?
var data = [{
product: 'ABC',
productId: 'AB123',
batch: 'BA1',
price: '12'
}, {
product: 'ABC',
productId: 'AB123',
batch: 'BA2',
price: '15'
}, {
product: 'ABC',
productId: 'AB113',
batch: 'BA2',
price: 15
}, {
product: 'XYZ',
productId: 'AB124',
batch: 'XY1',
price: '124'
}]
var unEs6 = function(x) {
if (x instanceof Map) {
var result = {}
for (let [key, value] of x.entries()) {
result[key] = unEs6(value);
}
return result;
}
else {
return x
}
}
JSON.stringify(unEs6(
data
.map(
row => (new Map().set(
row.product, new Map().set(
row.productId, new Map()
.set("batch", [row.batch])
.set("price", [row.price])
)
)
)
)
.reduce((a, b) => !a.has(b.keys().next().value) ?
new Map([...a, ...b]) :
!a.get(b.keys().next().value).has(b.get(b.keys().next().value).keys().next().value) ?
a.set(b.keys().next().value, new Map([
...a.get(b.keys().next().value),
...b.get(b.keys().next().value)
])) :
a.set(b.keys().next().value, a.get(b.keys().next().value).set(
b.get(b.keys().next().value).keys().next().value,
new Map()
.set("batch", a.get(b.keys().next().value).get(b.get(b.keys().next().value).keys().next().value).get("batch")
.concat(b.get(b.keys().next().value).get(b.get(b.keys().next().value).keys().next().value).get("batch"))
)
.set("price", a.get(b.keys().next().value).get(b.get(b.keys().next().value).keys().next().value).get("price")
.concat(b.get(b.keys().next().value).get(b.get(b.keys().next().value).keys().next().value).get("price"))
)
))
)
))

ImmutableJS: merge two list of objects, without duplicating them

Supposing I have the below:
var allFoods = Immutable.List();
var frenchFood = Immutable.List([
{
'type': 'french fries',
'price': 3
},
{
'type': 'petit gateau',
'price': 40
},
{
'type': 'croissant',
'price': 20
},
]);
var fastFood = Immutable.List([
{
'type': 'cheeseburger',
'price': 5
},
{
'type': 'vegan burger',
'price': 20
},
{
'type': 'french fries',
'price': 3
}
]);
I want to merge both lists, in a way that I also remove dupes (in this case, french fries), so the expected result would be:
{
'type': 'french fries', // keep the first french fries
'price': 3
},
{
'type': 'petit gateau',
'price': 40
},
{
'type': 'croissant',
'price': 20
},
{
'type': 'cheeseburger',
'price': 5
},
{
'type': 'vegan burger',
'price': 20
}
What I'm trying (doesn't remove dupes):
allFoods = frenchFood.concat(fastFood);
allFoods = allFoods.filter(function(item, pos) {
return allFoods.indexOf(item) === pos;
});
Which returns arrays merged, but still duplicated.
What am I missing?
const allFoods = frenchFood.concat(fastFood.filter((item) =>
frenchFood.indexOf(item) < 0
));
I would use reduce
var result = frenchFood.concat(fastFood).reduce( (reduction, food) => {
if(reduction[food.type]) {
return reduction;
} else {
return reduction.set([food.type], food);
}
}, new Immutable.Map()).valueSeq().toList();
I would highly encourage you to not nest js objects inside immutable structures. Better to wrap those objects in an Immutable.Map() or do Immutable.fromJS(yourJsObj).
Least amount of code
const results = Immutable.Set(frenchFood).union(Immutable.Set(fastFood));
However #rooftop answer fastest
https://jsperf.com/union-vs-concat-immutable
I found a best solution (for me) on medium, link to origin answer is dead: https://medium.com/#justintulk/merging-and-deduplicating-data-arrays-with-array-reduce-efaa4d7ef7b0
const arr1 = [
{ id: 1, name: 'Array 1-1' },
{ id: 2, name: 'Array 1-2' },
{ id: 3, name: 'Array 1-3' }
]
const arr2 = [
{ id: 1, name: 'Array 2-1' },
{ id: 3, name: 'Array 2-3' },
{ id: 4, name: 'Array 2-4' }
]
const mergeArrObjectsUnique = (currentArr, newArr) => {
let obj = {}
currentArr.forEach(item => {
obj[item.id] = item
})
newArr.forEach(item => {
obj[item.id] = item
})
let result = [];
for(let p in obj) {
if(obj.hasOwnProperty(p))
result.push(obj[p])
}
console.log('result: ', result)
return result
}
mergeArrObjectsUnique(arr1, arr2)

How can I make a JSON Object containing two properties from a JSON Object containing four properties

I have a JSON object like this:
[
{'car':'punto','brand':'fiat','color':'black','model':'2007'},
{'car':'XUV500','brand':'Mahindra','color':'black','model':'2008'},
{'car':'Eartiga','brand':'Maruti','color':'black','model':'2009'}
]
I want to achieve this:
[
{'car':'punto','brand':'fiat'},
{'car':'XUV500','brand':'Mahindra'},
{'car':'Eartiga','brand':'Maruti'}
]
How can I achieve it using javascript and Jquery. Any help isappreciated!
UPDATE 2022
You could just map the wanted properties by destructuring and short hand properties.
const
data = [{ car: 'punto', brand: 'fiat', color: 'black', model: '2007' }, { car: 'XUV500', brand: 'Mahindra', color: 'black', model: '2008' }, { car: 'Eartiga', brand: 'Maruti', color: 'black', model: '2009' }],
result= data.map(({ car, brand }) => ({ car, brand }));
console.log(result);
Depending on the need, you have basically two possibillities to tackle the problem:
rebuild the array with new objects, keeps the original array;
delete unwanted properties from each object, which modifies the original array.
var data = [{ 'car': 'punto', 'brand': 'fiat', 'color': 'black', 'model': '2007' }, { 'car': 'XUV500', 'brand': 'Mahindra', 'color': 'black', 'model': '2008' }, { 'car': 'Eartiga', 'brand': 'Maruti', 'color': 'black', 'model': '2009' }],
data1 = data.map(function (a) {
return { car: a.car, brand: a.brand };
});
data.forEach(function (a) {
delete a.color;
delete a.model;
})
document.write('<pre>' + JSON.stringify(data, 0, 4) + '</pre>');
document.write('<pre>' + JSON.stringify(data1, 0, 4) + '</pre>');
you can use map function in javascript
try this
x = [{
'car': 'punto',
'brand': 'fiat',
'color': 'black',
'model': '2007'
}, {
'car': 'XUV500',
'brand': 'Mahindra',
'color': 'black',
'model': '2008'
}, {
'car': 'Eartiga',
'brand': 'Maruti',
'color': 'black',
'model': '2009'
}]
var result = x.map(function(v) {
return {
car: v.car,
brand: v.brand
}
})
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>')
You can loop through each item in the array and create a new array with the data you want.
var originalArray = [{
'car': 'punto',
'brand': 'fiat',
'color': 'black',
'model': '2007'
}, {
'car': 'XUV500',
'brand': 'Mahindra',
'color': 'black',
'model': '2008'
}, {
'car': 'Eartiga',
'brand': 'Maruti',
'color': 'black',
'model': '2009'
}];
var newArray = [];
for (var i = 0; i < originalArray.length; i++) {
var originalItem = originalArray[i];
newItem = {
car: originalItem.car,
brand: originalItem.brand
};
newArray.push(newItem);
}
console.debug(newArray);
var oldJson = [
{'car':'punto','brand':'fiat','color':'black','model':'2007'},
{'car':'XUV500','brand':'Mahindra','color':'black','model':'2008'},
{'car':'Eartiga','brand':'Maruti','color':'black','model':'2009'}
];
var newJson = [];
for(var key in oldJson) {
newJson.push({
'car' : oldJson[key].car,
'brand' : oldJson[key].brand
})
}
console.log(newJson);
Try this method :
function getIwanttoList() {
var data = [
{
'text': '----- Select what you want -----',
'value': '',
}, {
'text': 'Ask a question',
'value': 'AskAQuestion',
}, {
'text': 'Report a content issue',
'value': 'ReportContentIssue',
}, {
'text': 'Propose an idea or quality improvement',
'value': 'ProposeImprovements',
}, {
'text': 'Submit content for governance',
'value': 'SubmitContent',
}
];
return data;
}

Categories

Resources