Convert Object which has value an Array to another Array of Object - javascript

I have this kind of object:
{
"John":[
{
"address":"xxx1",
"city":"yyy1"
},
{
"address":"xxx2",
"city":"yyy2"
}
],
"Doe":[
{
"address":"aaaa1",
"city":"aaa1"
}
],
"Smith":[
{
"address":"bbb1",
"city":"bbb1"
}
],
}
What I try to achieve is to reduce this object so it look like this:
[
{
"name":"John",
"address":"xxx1",
"city":"yyy1"
},
{
"name":"John",
"address":"xxx2",
"city":"yyy2"
},
{
"name":"Doe",
"address":"aaaa1",
"city":"aaaa1"
},
{
"name":"Smith",
"address":"bbb1",
"city":"bbb1"
}
]
But I'm sure that the same thing can be done somehow by using the ES6 array.reduce. Can you help me? I looked at JS (ES6): Reduce array based on object attribute but I can't figure it out.
const modifiedData = Object.entries(data).reduce(function (acc, [key,value]) {
const personName = key;
return [
...acc,
{
Agent: personName ,
adress: value.adress
},
];
}, []);

You can achieve this using reduce.
const obj = {
John: [
{
address: "xxx1",
city: "yyy1",
},
{
address: "xxx2",
city: "yyy2",
},
],
Doe: [
{
address: "aaaa1",
city: "aaa1",
},
],
Smith: [
{
address: "bbb1",
city: "bbb1",
},
],
};
const result = Object.entries(obj).reduce((acc, [key, arr]) => {
const collection = arr.map((a) => ({ name: key, ...a }));
acc = [...acc, ...collection];
return acc;
}, []);
console.log( result );

The simple way like this.
const data = {"John":[{"address":"xxx1","city":"yyy1"},{"address":"xxx2","city":"yyy2"}],"Doe":[{"address":"aaaa1","city":"aaa1"}],"Smith":[{"address":"bbb1","city":"bbb1"}],};;
const result = Object.entries(data).flatMap(([key, values]) =>
values.map(o => ({name: key, ...o})));
console.log(result);

If you want to do it using Array.prototype.reduce, you can do something like this:
const input = {
"John": [{
"address": "xxx1",
"city": "yyy1"
},
{
"address": "xxx2",
"city": "yyy2"
}
],
"Doe": [{
"address": "aaaa1",
"city": "aaa1"
}
],
"Smith": [{
"address": "bbb1",
"city": "bbb1"
}],
}
// 1. Using Object.keys()
const output1 = Object.keys(input).reduce((acc, person) => {
input[person].forEach(item => {
acc.push({ name: person, ...item })
})
return acc;
}, []);
console.log('output1:', output1)
// 2. Using Object.entries()
const output2 = Object.entries(input).reduce((acc, [key, value]) => {
value.forEach(item => {
acc.push({ name: key, ...item })
});
return acc;
}, [])
console.log('output2:', output2);

Related

Javascript: Remove Value from array inside an array of Object based on key

I have an array like this .
{
"filters": [
{
"filterProperty": "companyType",
"filterValues": [
"Private"
]
},
{
"filterProperty": "city",
"filterValues": [
"Mumbai",
"SanJose",
"Shanghai"
]
}
]
}
I have applied Filters. now I am removing them One by One and calling an API with remaining Filters.
so when I pass filterProperty as "city" and value as "Mumbai" then only "Mumbai" would remove from filterProperty "city" . the rest filter values should be same.
How can I do so ?
"filters": [
{
"filterProperty": "companyType",
"filterValues": [
"Private"
]
},
{
"filterProperty": "city",
"filterValues": [
"Mumbai",
"SanJose",
"Shanghai"
]
}
]
let data = filters.splice(a=> a.filterProperty === 'city' && a.filterValues.filter(a => a == "Mumbai"))
I assume you need map along with filter. Something like this:
const obj = { "filters": [ { "filterProperty": "companyType", "filterValues": [ "Private" ] }, { "filterProperty": "city", "filterValues": [ "Mumbai", "SanJose", "Shanghai" ] } ]};
const result = obj.filters.map(k=>(k.filterProperty == "city" ? (k.filterValues = k.filterValues.filter(o=>o!=='Mumbai'), k) : k ));
console.log(result);
Use Array.reduce()
let filters=[{filterProperty:"companyType",filterValues:["Private"]},{filterProperty:"city",filterValues:["Mumbai","SanJose","Shanghai"]}];
let data = filters.reduce((acc,cur) => {
if(cur.filterProperty === "city"){
cur.filterValues.splice(cur.filterValues.indexOf("Mumbai"),1)
}
acc.push(cur)
return acc
},[])
console.log(data)
Without mutating the data, use forEach and filter build new array of items.
const filter = (obj, prop, value) => {
const filters = [];
obj.filters.forEach(({ filterProperty, filterValues }) => {
filters.push({
filterProperty,
filterValues: filterValues.filter((item) =>
filterProperty === prop ? item != value : true
),
});
});
return {
filters,
};
};
const data = {
filters: [
{
filterProperty: "companyType",
filterValues: ["Private"],
},
{
filterProperty: "city",
filterValues: ["Mumbai", "SanJose", "Shanghai"],
},
],
};
const prop = "city";
const value = "Mumbai";
console.log(filter(data, prop, value));
Solution with mutating the data, using find and splice
const data = {
filters: [
{
filterProperty: "companyType",
filterValues: ["Private"],
},
{
filterProperty: "city",
filterValues: ["Mumbai", "SanJose", "Shanghai"],
},
],
};
const prop = "city";
const value = "Mumbai";
const city = data.filters.find(({ filterProperty }) => filterProperty === prop);
if (city) {
const index = city.filterValues.findIndex((item) => item === value);
if (index > -1) {
city.filterValues.splice(index, 1);
}
}
console.log(data);

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

How to create the object based on id and merge the inner key into an array JavaScript

I have a list of product each list have product code, parent id and product name. when I click product I am pushing into an array of an object listed below.
[
{"pid":"1","pcode":"van","pname":"mobile"},
{"pid":"1","pcode":"van","pname":"hphone"},
{"pid":"2","pcode":"car","pname":"wphone"},
{"pid":"2","pcode":"car","pname":"email"},
{"pid":"4","pcode":"bus","pname":"sms"}
]
how to create the object group based on id and merge the key3 into an array.
{
"pid":"1",
"details":[
{
"pcode":"van",
"pname":["mobile","hphone"]
}
]
},
{
"pid":"2",
"details":[
{
"pcode":"car",
"pname":["wphone","email"]
}
]
},
{
"pid":"3",
"details":[
{
"pcode":"bus",
"pname":["sms"]
}
]
}
I would use .reduce() for this scenario thus inside you can use .find() to create the desired output. The last pid for bus should be 4 instead of 3 anyway based on the listed array.
Try the following:
const data = [ {"pid":"1","pcode":"van","pname":"mobile"},{"pid":"1","pcode":"van","pname":"hphone"},{"pid":"2","pcode":"car","pname":"wphone"},{"pid":"2","pcode":"car","pname":"email"}, {"pid":"4","pcode":"bus","pname":"sms"}];
const result = data.reduce((a, c) => {
const found = a.find(e => e.pid === c.pid);
if (found) found.details[0].pname.push(c.pname);
else a.push({ pid: c.pid, details: [
{ pcode: c.pcode, pname: [ c.pname ] }
]});
return a;
}, []);
console.log(result);
I hope this helps!
Use .reduce can be done very easily and one for in loop to collect
result. faster result
const data = [
{ pid: "1", pcode: "van", pname: "mobile" },
{ pid: "1", pcode: "something", pname: "hphone" },
{ pid: "1", pcode: "van", pname: "hphone" },
{ pid: "2", pcode: "car", pname: "wphone" },
{ pid: "2", pcode: "car", pname: "email" },
{ pid: "4", pcode: "bus", pname: "sms" }
];
let result = data.reduce((map, cur) => {
if (!map[cur.pid]) {
map[cur.pid] = {
pid: cur.pid,
details: []
}
}
let hasMatch = false
map[cur.pid].details.forEach(x => {
if (x.pcode == cur.pcode) {
hasMatch = true
x.pname.push(cur.pname)
}
})
if (!hasMatch) {
map[cur.pid].details.push({
pcode: cur.pcode,
pname: [cur.pname]
})
}
return map
}, {})
let finalResult = []
for (const r in result) {
finalResult.push(result[r])
}
console.log(JSON.stringify(finalResult, null, 4));
It is possbible to use reduce method to create grouped array by pid. Then we can use map method to assign sequantial pid:
const obj = arr.reduce((a, {pid, pcode, pname}) => {
a[pid] = a[pid] || {pid, details: []};
if (a[pid].details.length === 0)
a[pid].details.push({pcode, pname:[pname]});
else
a[pid].details[0].pname.push(pname);
return a;
}, {})
const result = Object.values(obj).map((v, index) => ({...v, pid: ++index,}))
console.log(result);
An example:
let arr = [
{"pid":"1","pcode":"van","pname":"mobile"},
{"pid":"1","pcode":"van","pname":"hphone"},
{"pid":"2","pcode":"car","pname":"wphone"},
{"pid":"2","pcode":"car","pname":"email"},
{"pid":"4","pcode":"bus","pname":"sms"}
];
const obj = arr.reduce((a, {pid, pcode, pname}) => {
a[pid] = a[pid] || {pid, details: []};
if (a[pid].details.length === 0)
a[pid].details.push({pcode, pname:[pname]});
else
a[pid].details[0].pname.push(pname);
return a;
}, {})
const result = Object.values(obj).map((v, index) => ({...v, pid: ++index,}))
console.log(result);

Relate and merge array of same Department

I am working on an application where I need to get combine the object of same department based on the
conditions provided in the second Array and attach the relation to the object.
let inArr1 = [{"D1D2":"AND"},{"D3D4":"OR"}]
let inArr2 =[{"ID":"1","NAME":"KEN","DEPT1":"CSE"},
{"ID":"2","NAME":"MARK","DEPT2":"IT"},
{"ID":"3","NAME":"TOM","DEPT3":"ECE"},
{"ID":"4","NAME":"SHIV","DEPT4":"LIB"},
{"ID":"5","NAME":"TIM","DEPT5":"SEC"}
]
Output
outArr ={
[{"ID":"1","NAME":"KEN","DEPT1":"CSE","REL":"AND"},
{"ID":"2","NAME":"MARK","DEPT2":"IT","REL":"AND"}], //Arr1
[{"ID":"3","NAME":"TOM","DEPT3":"ECE","REL":"OR"},
{"ID":"4","NAME":"SHIV","DEPT4":"LIB","REL":"OR"}], //Arr2
[{"ID":"5","NAME":"TIM","DEPT5":"SEC"}] //Arr3
}
Code:
let condArr=[],outArr,i=1;
inArr1.forEach(condt => {
let dept = Object.keys(condt)[0];
let tmparr = dept.split("D");
tmparr.shift()
condArr.push(tmparr)
});
inArr2.forEach(condt => {
if(condArr.includes(inArr2.D+i)){
i++;
outArr.push(inArr2);
}
});
Your code has a bit confused logic, i would suggest rather this
let inArr1 = [{"D1D2":"AND"},{"D3D4":"OR"},{"D5D6":"AND"}]
let inArr2 =[{"ID":"1","NAME":"KEN","DEPT1":"CSE"},
{"ID":"2","NAME":"MARK","DEPT2":"IT"},
{"ID":"3","NAME":"TOM","DEPT3":"ECE"},
{"ID":"4","NAME":"SHIV","DEPT4":"LIB"},
{"ID":"5","NAME":"TIM","DEPT5":"SEC"},
{"ID":"6","NAME":"TLA","DEPT6":"SEC"},
]
// first lets create object of ids as keys and conditions as values
const [keys, conditions] = inArr1.reduce((agg, cond, index) => {
Object.entries(cond).forEach(([key, value]) => {
key.split('D').forEach(v => { if (v) agg[0][v] = { value, index }})
agg[1].push([])
})
return agg
}, [{}, []]) // {1: "AND", 2: "AND", 3: "OR", 4: "OR"}
conditions.push([])
// and now just map over all elements and add condition if we found id from the keys
inArr2.forEach(item => {
const cond = keys[item.ID]
if (cond) conditions[cond.index].push({...item, REL: cond.value})
else conditions[conditions.length - 1].push(item)
})
const res = conditions.filter(v => v.length)
console.log(res)
You could store the goups by using the ID and use new objects.
let inArr1 = [{ D1D2: "AND" }, { D3D4: "OR" }],
inArr2 = [{ ID: "1", NAME: "KEN", DEPT1: "CSE" }, { ID: "2", NAME: "MARK", DEPT2: "IT" }, { ID: "3", NAME: "TOM", DEPT3: "ECE" }, { ID: "4", NAME: "SHIV", DEPT4: "LIB" }, { ID: "5", NAME: "TIM", DEPT5: "SEC" }],
groups = inArr1.reduce((r, o) => {
Object.entries(o).forEach(([k, REL]) => {
var object = { REL, group: [] };
k.match(/[^D]+/g).forEach(id => r[id] = object);
});
return r;
}, {}),
grouped = inArr2.reduce((r, o) => {
var { REL, group } = groups[o.ID] || {};
if (group) {
if (!group.length) r.push(group);
group.push(Object.assign({}, o, { REL }));
} else {
r.push([o]);
}
return r;
}, []);
console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }
can try other solution:
let inArr1 = [{ D1D2: "AND" }, { D3D4: "OR" }, { D6D7: "XOR" }];
let inArr2 = [
{ ID: "1", NAME: "KEN", DEPT1: "CSE" },
{ ID: "2", NAME: "MARK", DEPT2: "IT" },
{ ID: "3", NAME: "TOM", DEPT3: "ECE" },
{ ID: "4", NAME: "SHIV", DEPT4: "LIB" },
{ ID: "5", NAME: "TIM", DEPT5: "SEC" },
{ ID: "9", NAME: "BAR", DEPT5: "XYZ" },
{ ID: "6", NAME: "FOO", DEPT5: "XYZ" },
];
let unmatchedArr = []
let matchedArr = inArr2.reduce((acc, obj) => {
// getting index matched from inArr1 objects key
const indexMatched = getIndexMatch(obj.ID);
// creating index if not exists
if (!acc[indexMatched] && indexMatched !== null) acc[indexMatched] = [];
// if some index matched it merge current obj with DEL property with inArr1[indexMatched] key => value
return indexMatched !== null
? acc[indexMatched].push({
...obj,
DEL: inArr1[indexMatched][Object.keys(inArr1[indexMatched])[0]]
})
// pushing on unmatchedArr
: unmatchedArr.push(obj)
, acc
}, []);
function getIndexMatch(id) {
for (const [index, obj] of inArr1.entries()) {
for (const key of Object.keys(obj)) {
// spliting only digits of the current key of object
if (key.match(/\d/g).includes(id)) return index; // returning index of inArr1 if is included
}
}
return null;
}
// merging arrays
const result = [...matchedArr, unmatchedArr];
console.log(result);

How to extract object from another object?

I have this array object, and I'm trying to create another object out of it. I already have a solution but I think there may be a shorter way of doing what I'm doing. Does anyone know how to make this code shorter or another way using lodash or pure javascript? Thanks a lot in advance!
{
firstName: Mike,
lastName : Brown
}
so far my code works and looks like this:
let response = [
{
"Name": "hobby",
"Value": "poker"
},
{
"Name": "privacy_id",
"Value": "1112"
}, {
"Name": "given_name",
"Value": "Mike"
},
{
"Name": "family_name",
"Value": "Brown"
},
{
"Name": "email",
"Value": "test#email.com"
}
]
const newObj = {};
_.forEach(response, function(obj) {
if(obj.Name === 'given_name') { newObj.firstName = obj.Value}
if(obj.Name === 'family_name'){ newObj.lastName = obj.Value}
});
console.log(newObj);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
This is a good usecase for Array.prototype.reduce since what you want is to transform an array into something - something being an object in your case:
const newObj = response.reduce((acc, curr) => {
acc[curr.Name] = curr.Value;
return acc;
}, {});
This would transform:
const response = [
{
'Name': 'given_name',
'Value': 'Mike'
},
{
'Name': 'family_name',
'Value': 'Brown'
}
]
into:
{
'given_name': 'Mike',
'family_name': 'Brown'
}
Now, if you want to change the naming of the key, you could use some sort of mapping:
const NameMapping = {
given_name: 'firstName',
family_name: 'lastName'
};
const response = [
{
'Name': 'given_name',
'Value': 'Mike'
},
{
'Name': 'family_name',
'Value': 'Brown'
}
]
const newObj = response.reduce((acc, curr) => {
if (NameMapping[curr.Name] === undefined)
return acc;
acc[NameMapping[curr.Name]] = curr.Value;
return acc;
}, {});
So your newObj would look like this:
{
firstName: 'Mike',
familyName: 'Brown'
}
If you are sure that response contains both the object with the key given_name and the object with the key family_name, you could write this way:
const newObj = {
'given_name': response.filter(el => el.Name ==='given_name')[0].Value,
'family_name': response.filter(el => el.Name ==='family_name')[0].Value,
}
There's the fiddle:
let response = [
{
"Name": "hobby",
"Value": "poker"
},
{
"Name": "privacy_id",
"Value": "1112"
}, {
"Name": "given_name",
"Value": "Mike"
},
{
"Name": "family_name",
"Value": "Brown"
},
{
"Name": "email",
"Value": "test#email.com"
}
]
const newObj = {
'given_name': response.filter(el => el.Name ==='given_name')[0].Value,
'family_name': response.filter(el => el.Name ==='family_name')[0].Value,
}
console.log(newObj);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

Categories

Resources