Create new object with unique elements from objects of array of objects - javascript

I have an Array of Objects. Every object in this Array has some Keypairs. One of this Keypairs ("obj", for example) is an Array of Objects too.
Example what I have:
const arrOfObj = [
{
"id": 1
"obj": {
"arr1": ["arr1-1"],
"arr2": ["arr2-1", "arr2-2"],
"arr3": ["arr3-1", "arr3-2"]
}
},
{
"id": 1
"obj": {
"arr1": ["arr1-2"],
"arr2": ["arr2-1", "arr2-3"],
"arr3": ["arr3-1", "arr3-3"],
"arr4": ["arr4-1"],
}
},
];
I need to get new Object of "obj" Objects with unique keys and unique elements inside them.
Example what I need:
const newObj = {
"arr1": ["arr1-1", "arr1-2"],
"arr2": ["arr2-1", "arr2-2", "arr2-3"],
"arr3": ["arr3-1", "arr3-2", "arr3-3"],
"arr4": ["arr4-1"],
}
All of this comes dynamically from API by request, so I don`t know the names of this keypairs, but i need to store them.
I have Solution, but I`m new in JavaScript, and want to know how to simplify and improve my poor Code.
1. First, I`m defining the new Object and retrieving the Names for his keypairs from "arrOfObj".
let filterObj = {};
arrOfObj.forEach(function (item) {
for (let key in item.obj) {
filterObj[key] = [];
}
});
2. After that I`m getting all the Elements of every Array from "arrOfObj" and store them in new Object "filterObj" in the Keypair with the same Name.
arrOfObj.forEach(function (item) {
for (let key in item.obj) {
for (let element = 0; element < item.obj[key].length; element++) {
filterObj[key].push(item.obj[key][element]);
}
}
});
3. To the end I`m filtering Arrays to get unique Elements only.
for (let key in filterObj) {
filterObj[key] = Array.from(new Set(filterObj[key]));
}
It works, I`ve got what I want, but it seems to much monstrously. How this code can be simplified the best way?
Thanks for the help and advices.

You can use some destructuring and Object.entries() and Object.keys() to streamline this and do everything to the new Object only
const newObj = {}
arrOfObj.forEach(({obj}) => {
Object.entries(obj).forEach(([k, arr]) => {
newObj[k] = newObj[k] || [];
newObj[k].push(...arr);
})
});
Object.keys(newObj).forEach(k => newObj[k] = [...new Set(newObj[k])]);
console.log(newObj)
<script>
const arrOfObj=[{id:1,obj:{arr1:["arr1-1"],arr2:["arr2-1","arr2-2"],arr3:["arr3-1","arr3-2"]}},{id:1,obj:{arr1:["arr1-2"],arr2:["arr2-1","arr2-3"],arr3:["arr3-1","arr3-3"],arr4:["arr4-1"]}}];
</script>

Another solution using Object#fromEntries, Array#reduce, Object#entries, Array#forEach, Set, and Map:
const arrOfObj = [ { "id": 1, "obj": { "arr1": ["arr1-1"], "arr2": ["arr2-1", "arr2-2"], "arr3": ["arr3-1", "arr3-2"] } }, { "id": 1, "obj": { "arr1": ["arr1-2"], "arr2": ["arr2-1", "arr2-3"], "arr3": ["arr3-1", "arr3-3"], "arr4": ["arr4-1"] } } ];
const filterObj =
// transform the resulting list of key-values pairs to an object at the end
Object.fromEntries(
// get a map of array name as key and its unique items as value
[...arrOfObj.reduce((map, { obj = {} }) => {
// iterate over current element's object to update the map
Object.entries(obj).forEach(([currentKey, currentValues]) => {
const keyValues = [...(map.get(currentKey) || []), ...currentValues];
map.set(currentKey, [...new Set(keyValues)]);
});
return map;
}, new Map)]
);
console.log(filterObj);

Related

Javascript conditionally adding the nested object using map() operator

I have a below JSON,
var original = {
"todos": [
{
"accountNo": "50190000",
"name": "Sarkar",
"vpainfo": [
{
"vpa": "log#bda",
"mccCode": "0000"
}
]
}
]
}
And am trying to add new data inside the nested array i.e., "vpainfo". I have tried using the below code and able to adding the new values inside "vpainfo".
var newdata = {"vpa":"first#bda","mccCode":"1111"};
var newObj =
Object.assign({}, original,
{
todos: original.todos.map(todoInfo=>(todoInfo.accountNo=="50190000")?[
...todoInfo.vpainfo,
newdata
]: todoInfo)
});
And the resulted object is,
{"todos":[[{"vpa":"log#bda","mccCode":"0000"},{"vpa":"first#bda","mccCode":"1111"}]]}
But few of the key and values(accountNo and name) are getting missed, how do we get the full object with the latest updated values?
You only return the array, not the actual object, hence the error.
var original = {
"todos": [
{
"accountNo": "50190000",
"name": "Sarkar",
"vpainfo": [
{
"vpa": "log#bda",
"mccCode": "0000"
}
]
}
]
}
const newdata = {"vpa":"first#bda","mccCode":"1111"};
const newObj = Object.assign({}, original,
{
todos: original.todos.map(todoInfo=>{
if(todoInfo.accountNo=="50190000"){
return {
...todoInfo,
vpainfo: [...todoInfo.vpainfo, newdata]
}
}
return todoInfo
})
});
console.log(newObj)
All those spread operators seem a little excessive...
If all you wanna do is add newdata to that existing array, then do that:
var original = {
"todos": [{
"accountNo": "50190000",
"name": "Sarkar",
"vpainfo": [{
"vpa": "log#bda",
"mccCode": "0000"
}]
}]
};
const newdata = {
"vpa": "first#bda",
"mccCode": "1111"
};
// Find the correct account.
const account = original.todos.filter(t => t.accountNo === '50190000')[0];
if (account) {
account.vpainfo.push(newdata);
}
console.log(original);

Filter an array of objects, by keys in filter object

i'm new here, i have problem that i can not solve.
I have 2 different arrays:
The first array - contains ratings of users with their ID name
[
{"handle":"frontend1", "_redis":"3", "_nodejs":"5", "_mysql":"2", "_python":"3", "_mongo":"4"},
{"handle":"frontend3", "_php":"4", "_mysql":"4", "_oracle":"4", "_ruby":"3", "_mongo":"5", "_python":"5"},
{"handle":"frontend4", "_java":"5", "_ruby":"5", "_mysql":"5", "_mongo":"5"}
]
The second set - contains the ratings, which I want to return to each user.
If there is a rating that is not in the second set, I will not return it
In the second set, values do not matter, only keys
[
"_assembler",
"_css",
"_python",
"_php"
]
I want to return to the first set, the handle, and all the rankings that exist in the second set.
[
{"handle":"frontend1", "_python":"3" },
{"handle":"frontend3", "_php":"4", "_python":"5" },
{"handle":"frontend4"}
]
this is what i try to do.
keys = [
"_assembler",
"_css",
"_python",
"_php"
]
source = [
{"handle":"frontend1", "_redis":"3", "_nodejs":"5", "_mysql":"2", "_python":"3", "_mongo":"4"},
{"handle":"frontend3", "_php":"4", "_mysql":"4", "_oracle":"4", "_ruby":"3", "_mongo":"5", "_python":"5"},
{"handle":"frontend4", "_java":"5", "_ruby":"5", "_mysql":"5", "_mongo":"5"}
];
result = [];
tmp = {};
source.forEach((item) => {
Object.keys(item).map(({key,value}) =>
{
if(key == "handle")
{
tmp[key]=value;
}
if(keys.includes(key))
{
tmp[key]=value;
}
})
result.push(...tmp);
tmp = {};
});
You can do this with a map utilizing a couple of other array methods such as filter, and Object methods.
const keys = [
"_assembler",
"_css",
"_python",
"_php"
]
const source = [
{"handle":"frontend1", "_redis":"3", "_nodejs":"5", "_mysql":"2", "_python":"3", "_mongo":"4"},
{"handle":"frontend3", "_php":"4", "_mysql":"4", "_oracle":"4", "_ruby":"3", "_mongo":"5", "_python":"5"},
{"handle":"frontend4", "_java":"5", "_ruby":"5", "_mysql":"5", "_mongo":"5"}
];
const result = source.map( s => ({
handle: s.handle,
...Object.fromEntries(Object.entries(s).filter(x => x[0] != "handle" && keys.includes(x[0])))
}));
console.log(result);

Javascript - how to loop through dict inside a list

So I am pretty new when it comes to Javascript and it is as simple as read a json list with a value of:
{
"URL": [{
"https://testing.com/en/p/-12332423/": "999"
}, {
"https://testing.com/en/p/-123456/": "123"
},
{
"https://testing.com/en/p/-456436346/": "422"
}
]
}
What I would like to do is to have both the URL and the amount of numbers etc
"https://testing.com/en/p/-12332423/" and "999"
and I would like to for loop so it runs each "site" one by one so the first loop should be
"https://testing.com/en/p/-12332423/" and "999"
second loop should be:
"https://testing.com/en/p/-123456/" and "123"
and so on depending on whats inside the json basically.
So my question is how am I able to loop it so I can use those values for each loop?
As Adam Orlov pointed out in the coment, Object.entries() can be very useful here.
const URLobj = {
"URL": [{
"https://testing.com/en/p/-12332423/": "999"
}, {
"https://testing.com/en/p/-123456/": "123"
},
{
"https://testing.com/en/p/-456436346/": "422"
}
]
};
URLobj.URL.forEach(ob => {
console.log('ob', ob);
const entries = Object.entries(ob)[0]; // 0 just means the first key-value pair, but because each object has only one we can just use the first one
const url = entries[0];
const number = entries[1];
console.log('url', url);
console.log('number', number);
})
You mean something like this using Object.entries
const data = {
"URL": [
{"https://testing.com/en/p/-12332423/": "999"},
{"https://testing.com/en/p/-123456/": "123"},
{"https://testing.com/en/p/-456436346/": "422"}
]
}
data.URL.forEach(obj => { // loop
const [url, num] = Object.entries(obj)[0]; // grab the key and value from each entry - note the [0]
console.log("Url",url,"Number", num); // do something with them
})
let's call your object o1 for simplicity. So you can really go to town with this link - https://zellwk.com/blog/looping-through-js-objects/
or you can just use this code :
for(var i = 0; i < o1.URL.length; i++) {
//each entry
var site = Object.keys(URL[i]) [0];
var value = Object.values(URL[i]) [0];
// ... do whatever
}
don't forget each member of the array is an object (key : value) in its own right
You can extract the keys and their values into another object array using map
Then use the for loop on the newly created array. You can use this method on any object to separate their keys and values into another object array.
const data = {
"URL": [{
"https://testing.com/en/p/-12332423/": "999"
}, {
"https://testing.com/en/p/-123456/": "123"
},
{
"https://testing.com/en/p/-456436346/": "422"
}
]
}
var extracted = data.URL.map(e => ({
url: Object.keys(e)[0],
number: Object.values(e)[0]
}))
extracted.forEach((e) => console.log(e))

How to not display duplicates from many objects in an Array

How can I make sure that no duplicates are displayed with vue inside a template ?
I my case the data is an array of objects and key that has a value of an object with multiple objects within it. So this would be a nested v-for in vue template syntax.
{
"matches": [
{
"birthday": "1/29/2019",
"household": {
"0": {
"relationship": "brother"
},
"1": {
"relationship": "brother"
}
}
}
]
}
I would only like to display 1 unique relationship per household. Please see fiddle for further examination https://jsfiddle.net/sxmhv3t7/
You can use computed property to make matches array unique.
For example:
computed: {
uniqueMatches () {
return this.matches.map(item => {
let households = Object.values(item.household)
let relationships = households.map(item => item.relationship)
const uniqueRelationships = [...new Set(relationships)]
item.household = uniqueRelationships.reduce((acc, cur, idx) => {
acc[idx] = {}
acc[idx].relationship = cur
return acc
}, {})
console.log(item)
return item
})
}
}
and then use uniqueMatches instead of matches in template
Demo in jsfiddle
You could massage the data a bit and create a uniqueHouseholdMembers array property on each match in the matches array and then just print out those values:
matches.forEach(match => {
let houseHolds = Object.values(match.household);
match.uniqueHouseholdMembers = houseHolds.reduce((acc, household) => {
// check if household member has already been added to our growing list
let isUniqueRelationship = !acc.includes(household.relationship);
// add household member if unique
if (isUniqueRelationship) {
acc.push(household.relationship);
}
return acc;
}, []);
});
// output using the data you provided:
// match[0].uniqueHouseholdMembers -> ['brother']
// match[1].uniqueHouseholdMembers -> ['sister']
// and if you have a 3rd match entry with more household members:
// match[2].uniqueHouseholdMembers -> ['brother', 'father', 'stranger']

remove object from array if property value match

I have array of objects that look like:
{
"brandid": id,
"brand": string,
"id": id,
"categoryId": id,
"category": string,
"factory": string,
"series": string,
"status": 0,
"subStatus": 1
}
if the series property value matches another series property value in the other objects in the array, that object needs to be removed from the array.
Currently I have attempted to push them to a duplicate Array with :
const seriesResCopy = seriesRes;
const dupArray = []
for (const thing of seriesResCopy) {
for (const item of seriesRes) {
if (thing.series === item.series) {
dupArray.push(item);
}
}
}
but this does not work. From examples I have seem my issue has been that I do not have a definite list of duplicate values to look for.
Any help would be much appreciated.
You could use a Set of series to filter out duplicates:
const exists = new Set();
seriesRes = seriesRes.filter(({series}) => !exists.has(series) && exists.add(series));
This uses: Array.prototype.filter, Object destructuring and some logical tricks.
The same can be done by mutating the array:
const exists = new Set();
for(const [index, {series}] of seriesRes.entries()) {
if(!exists.has(series) {
exists.add(series);
} else {
seriesRes.splice(index, 1);
}
}
To filter duplicates from the array and keep the first instance:
let seriesWithoutDuplicates = seriesRes.filter((s, i, self) => {
return self.findIndex(z => z.series === s.series) === i;
});

Categories