Flattering objects + arrays + objects into one object javascript [duplicate] - javascript

This question already has answers here:
How can I access and process nested objects, arrays, or JSON?
(31 answers)
Closed 5 years ago.
I will go straight to the point, so here is what I have:
const someObj = {
one: [
{
id: 123,
text: "lalala"
},
{
id: 456,
text: "lalala2"
},
{
id: 789,
text: "lalala3"
}
],
two: [
{
id: 111,
text: "text random"
},
{
id: 222,
text: "text random2"
},
{
id: 333,
text: "text random3"
}
]
};
and this is what I need to have:
const someOtherObj = {
111: {
id: 111,
text: "text random"
},
222: {
id: 222,
text: "text random2"
},
333: {
id: 333,
text: "text random3"
},
123: {
id: 123,
text: "lalala"
},
456: {
id: 456,
text: "lalala2"
},
789: {
id: 789,
text: "lalala3"
}
};
I know this can be achieved without million loops, just I can't think of any smart solution. :/ So, maybe someone can help me to solve this puzzle? :)
Thanks :)

Try with Array#reduce function with ES6
first reduce created array with all inner Object
Second reduce used to create object key with id
const someObj = { one: [ { id: 123, text: "lalala" }, { id: 456, text: "lalala2" }, { id: 789, text: "lalala3" } ], two: [ { id: 111, text: "text random" }, { id: 222, text: "text random2" }, { id: 333, text: "text random3" } ] };
var res = Object.values(someObj).reduce((a,b)=> (b.forEach(val=> a.push(val)),a),[])
var f = res.reduce((a,b)=> (a[b.id] = b, a),{})
console.log(f)

You only need to use two loops, no more (using ES6 seeing that your example used it as well)
const newObj = {};
for(const key in someObj) {
for(let i = 0; i < someObj[key].length; i++) {
const obj = someObj[key][i];
newObj[obj.id] = {
id: obj.id,
text: obj.text
}
}
}

Related

JavaScript merge array objects with the same keys

I have an array with several objects some have the same keys (Question and QuestionId), for example:
var jsonData = [
{
Question: "Was the training useful?",
QuestionId: 1,
myData: [{ name: 'No', value: 1 }] },
{
Question: "Was the training useful?",
QuestionId: 1 ,
myData: [{ name: 'Yes', value: 1 }]
}];
How can I combine these objects into one, expected output:
var jsonData = [
{
Question: "Was the training useful?",
QuestionId: 1,
myData: [{ name: 'No', value: 1 },
{ name: 'Yes', value: 1 }]
}];
var jsonData = [{
Question: "Was the training useful?",
QuestionId: 1,
myData: [{
name: 'No',
value: 1
}]
},
{
Question: "Was the training useful?",
QuestionId: 1,
myData: [{
name: 'Yes',
value: 1
}]
}
];
const result = Object.values(jsonData.reduce((acc, obj) => {
if (!acc[obj.QuestionId]) {
acc[obj.QuestionId] = obj;
} else {
acc[obj.QuestionId].myData = acc[obj.QuestionId].myData ?? []; // if myData is null or undefined, set it to an empty array
acc[obj.QuestionId].myData = acc[obj.QuestionId].myData.concat(obj.myData);
}
return acc;
}, {}));
console.log(result);
function mergeData(data) {
const acc = {}
data.forEach(x => {
const id = x.QuestionId
if (!acc[id]) acc[id] = x
else acc[id].myData = acc[id].myData.concat(x.myData)
})
return Object.values(acc)
}
You can use forEach to create an object where the keys are the question IDs and then use Object.values to get the values into an array.
var jsonData = [{
Question: "Was the training useful?",
QuestionId: 1,
myData: [{ name: 'No', value: 1 }]
}, {
Question: "Was the training useful?",
QuestionId: 1 ,
myData: [{ name: 'Yes', value: 1 }]
}];
var temp = {};
jsonData.forEach(x=>{
if(!temp[x.QuestionId]) {temp[x.QuestionId] = x;}
else {temp[x.QuestionId].myData.push(x.myData);}
});
var arr = Object.values(temp);
console.log(arr);

Find Object Inside Array of Object Array

I currently have an array of objects with each containing an array of objects.
My goal is to find a nested object in a single line of javascript code. I am trying to avoid a nested loop, I know how to solve it that way but javascript offers a lot of elegant solutions for such scenarios.
This is how my data looks like:
const items = [
{
id: 1,
title: 'Test 1',
data: [
{
id: 3,
title: 'Test 3',
},
{
id: 4,
title: 'Test 4',
},
],
},
{
id: 2,
title: 'Test 2',
data: [
{
id: 5,
title: 'Test 5',
},
],
},
];
With a nested loop:
let item = null;
for (let i = 0; i<items.length; i++) {
for (let j = 0; j<items[i].data; j++) {
if (items[i].data[j].id == myId) {
item = items[i].data[j];
return;
}
}
}
I feel like there is a more simplistic and prettier solution than this.
You could do that in one line. As I saw in your nested loop solution, you find in each object's data, so first you could flatten the data in to array of objects and then find through that array
const items = [
{
id: 1,
title: "Test 1",
data: [
{
id: 3,
title: "Test 3",
},
{
id: 4,
title: "Test 4",
},
],
},
{
id: 2,
title: "Test 2",
data: [
{
id: 5,
title: "Test 5",
},
],
},
];
const myId = 4;
const res = items.flatMap((item) => item.data).find(({ id }) => id === myId);
console.log(res);
In terms of performance, I would suggest the way is to use Array#reduce combined with Array#find
const items = [{id:1,title:"Test 1",data:[{id:3,title:"Test 3",},{id:4,title:"Test 4",},],},{id:2,title:"Test 2",data:[{id:5,title:"Test 5",},],},];
const myId = 4;
const res = items.reduce((acc, {data}) => {
const foundItem = data.find(({id}) => id === myId);
if(foundItem)
acc.push(foundItem);
return acc;
}, [])
console.log(res);

Remove duplicate elements of an array, in an object of arrays, dynamically

I have checked other solutions but none fit the criterion of my problem
This solution does not have the ability to dynamically check each node
Problem summarized
I wish to create an algorithm that is able to check an object that has nodes of different data types, for duplicated objects in nodes that are specifically of the datatype array.
I have the following dataset:
task = {
content: "lorem....",
customer: [
{ id: 1, name: "hello" },
{ id: 2, name: "sup" },
],
end: "2020-08-13 10:09:48",
project: [{ id: 1 }, { id: 1 }, { id: 2 }],
vendor: [{ id: 2 }, { id: 2 }, { id: 3 }],
};
I wish to be able to dynamically check which of the objects (or nodes? and the algo has to recognize that it is an array) has duplicates, and reduce them to be in this form:
task = {
content: "lorem....",
customer: [
{ id: 1, name: "hello" },
{ id: 2, name: "sup" },
],
end: "2020-08-13 10:09:48",
project: [{ id: 1 }, { id: 2 }],
vendor: [{ id: 2 }, { id: 3 }],
};
EDIT
The algorithm needs to be able to handle a dynamic number of nodes (example 1), however , the duplicates will only happen 1 level down (Thanks for pointing out).
example 1 (there is 1 less node here ) :
task = {
content: "lorem....",
customer: [
{ id: 1, name: "hello" },
{ id: 2, name: "sup" },
],
end: "2020-08-13 10:09:48",
project: [{ id: 1 }, { id: 2 }],
};
Here is my proposed solution to remove duplicate elements from any array in the task object:
const uniq = array => {
const map = {};
const result = [];
for (let i = 0; i < array.length; i++) {
// since elements can be objects, need to do a deep comparison.
const element = JSON.stringify(array[i]);
if (map[element] === undefined) {
map[element] = true;
result.push(array[i]);
}
}
return result;
}
const task = {
content: "lorem....",
customer: [
{ id: 1, name: "hello" },
{ id: 2, name: "sup" },
],
end: "2020-08-13 10:09:48",
project: [{ id: 1 }, { id: 1 }, { id: 2 }],
vendor: [{ id: 2 }, { id: 2 }, { id: 3 }],
};
for (const key in task) {
if (Array.isArray(task[key])) {
task[key] = uniq(task[key])
}
}
console.log('deduped:', task);

How to traverse through 2 javascript array of objects and create a third one?

I have two objects. obj2 has texts and obj1 has 3 subIbjId. How can I add the 'id' to obj2 based on obj1?
For example: obj1 has 2 subObjId in the first object(1001, 1002). I want to count the number of subObjId obj1 has and iterate through obj1 and add the key and value of id for the to obj2. If obj1 has two subObjId, then add id: 1 to the first two entries of obj2 and so on.
I am learning javascript and trying to solve some imaginary problems. Any help would be greatly appreciated. Thank you.
var obj1 = { [
{
id: 1,
name: ‘apple’,
subObjId: [ 1001, 1002]
subObjs: [
{
subId: 1001
subName: ‘ant’,
},
{
subId: 1002
subName: ‘ball’,
}
],
},
{
{
id: 2,
name: ‘zebra’,
subObjId: [ 1003]
subObjs: [
{
subId: 1003
subName: ‘cat’,
}
],
},
]
}
var obj2 = { [
{
text: ‘i am a text’
},
{
text: ‘i am some random characters’
},
{
text: ‘i am some numbers’
}
] }
to become
finalObject = { [
{
id: 1,
text: ‘i am a text’
},
{
id: 1,
text: ‘i am some random characters’
},
{
id: 2,
text: ‘i am some numbers’
}
] }
Try this!!
var obj1 = [
{
id: 1,
name: 'apple',
subObjId: [ 1001, 1002]
},
{
id: 2,
name: 'zebra',
subObjId: [ 1003]
}
]
var obj2 = [
{
text: 'i am a text'
},
{
text: 'i am some random characters'
},
{
text: ' am some numbers'
}
]
let index = 0;
let start = 0;
obj1.map(data1=>{
index += data1.subObjId.length;
for(var i=start;i<index;i++){
obj2[i]['id'] = data1.id;
}
start = i;
})
console.log(obj2)
You can use
Array#flatMap to extract an array of all subObjs items
also Array#map them into their parent's id property only.
Perform another mapping operation that copies the contents of a matching object in obj2 and adds an id.
For convenience, this uses the second argument to Array#map, which sets the this context inside the callback.
Also uses destructuring for compactness and spread syntax for making copies:
var obj1 = [ { id: 1, name: 'apple', subObjId: [1001, 1002], subObjs: [ { subId: 1001, subName: 'ant' }, { subId: 1002, subName: 'ball' } ] }, { id: 2, name: 'zebra', subObjId: [1003], subObjs: [ { subId: 1003, subName: 'cat', } ], }, ];
var obj2 = [ { text: 'i am a text' }, { text: 'i am some random characters' }, { text: 'i am some numbers' } ];
var finalObject = obj1
//1. flatMap into a single array
.flatMap(({id, subObjs}) => subObjs
.map(sub => ({id})) //take only the parent ID for each sub object
)// result: [{id: 1}, {id: 1}, {id: 2}]
.map(function({id}, index) {
return { id, ...this[index] } //2. create a new object with the id and the content of a matching object from the other array
}, obj2);// <- set the `this` context for the callback
console.log(finalObject);
It can also be done as a single operation when flatmapping by setting the this context to a copy of the second array (to avoid mutating obj2), then taking items off the front of the new array with Array#shift:
var obj1 = [ { id: 1, name: 'apple', subObjId: [1001, 1002], subObjs: [ { subId: 1001, subName: 'ant' }, { subId: 1002, subName: 'ball' } ] }, { id: 2, name: 'zebra', subObjId: [1003], subObjs: [ { subId: 1003, subName: 'cat', } ], }, ];
var obj2 = [ { text: 'i am a text' }, { text: 'i am some random characters' }, { text: 'i am some numbers' } ];
var finalObject = obj1.flatMap(function({id, subObjs}) {
return subObjs.map(sub => ({ id, ...this.shift() }))
}, [...obj2]);// <- copy obj2 as the `this` context
console.log(finalObject);
Use this snippet
var obj1 = [
{
id: 1,
name: 'apple',
subObjId: [1001, 1002],
subObjs: [{
subId: 1001,
subName: 'ant',
},
{
subId: 1002,
subName: 'ball',
}
],
},
{
id: 2,
name: 'zebra',
subObjId: [1003],
subObjs: [{
subId: 1003,
subName: 'cat',
}],
},
]
var obj2 = [
{
text: 'i am a text'
},
{
text: 'i am some random characters'
},
{
text: 'i am some numbers'
}
]
var finalObject = obj1.map(function (value, index) {
return {
id: value.id,
text: obj2[index].text
}
})
console.log(finalObject)

How to get sum of array nested in object?

{service: {
categories: [
{
name: "category1",
id: 1,
questions: [
{
id: 1,
question: "example trivia question here",
value: 2
}, {
id: 2,
question: "example trivia question here",
value: 3
}]
},
{
name: "category2",
id: 2,
questions: [
{
id: 3,
question: "example trivia question here",
value: 5
}
]
},
{
name: "category3",
id: 3
}
]
}};
For each category, I'm trying to count the answered trivia question. How do I get the sum of answered questions for each category (indicated when there is a value present)? I think there's something gone wrong in my loop. I've also tried this with array prototypes. Sorry for the noob question.
$scope.questionCount = 0;
angular.forEach($scope.service, function(categories, questions) {
for (var i = 0; i < questions.length; i++) {
if (questions[i].value !== null){
triviaCount = 0
triviaCount += 1
$scope.questionCount.push(triviaCount)
}
}
});
Use map() method provided by Array
var service = {
categories: [
{
name: "category1",
id: 1,
questions: [
{
id: 1,
question: "example trivia question here",
value: 2
}, {
id: 2,
question: "example trivia question here",
value: 3
}]
},
{
name: "category2",
id: 2,
questions: [
{
id: 3,
question: "example trivia question here",
value: 5
}
]
},
{
name: "category3",
id: 3
}
]
};
var result = service.categories.map(function(cat) {
return {
'name' : cat.name,
'count' : !!cat.questions ? cat.questions.length : 0
}
});
console.log(result);
// [{ name="category1", count=2}, { name="category2", count=1}, { name="category3", count=0}]
I am not used to with angular js but this is how i will do with js. i hope this helps you.
var json = {
service: {
categories: [{
name: "category1",
id: 1,
questions: [{
id: 1,
question: "example trivia question here",
value: 2
}, {
id: 2,
question: "example trivia question here",
value: 3
}]
}, {
name: "category2",
id: 2,
questions: [{
id: 3,
question: "example trivia question here",
value: 5
}]
}, {
name: "category3",
id: 3
}]
}
};
var qCount = 0;
categories = json.service.categories;
for (var category in categories) {
var temp = categories[category];
if (temp.questions !== undefined) {
var questions = temp.questions;
for (var que in questions) {
if (questions[que].value !== undefined)
qCount++;
}
}
}
console.log(qCount); //here is your question count
something like this? (look at the console)
console output:
category1 # of quesitons: 2
category2 # of quesitons: 1
category3 # of quesitons: 0
var service = {
categories: [
{
name: "category1",
id: 1,
questions: [
{
id: 1,
question: "example trivia question here",
value: 2
}, {
id: 2,
question: "example trivia question here",
value: 3
},
{
id: 9,
question: "example trivia question here",
value: '',
}
]
},
{
name: "category2",
id: 2,
questions: [
{
id: 3,
question: "example trivia question here",
value: 5
},
{
id: 7,
question: "example trivia question here",
value: '',
}
]
},
{
name: "category3",
id: 3,
questions: [],
}
]
};
$(document).ready(function() {
for(var i = 0; i < service.categories.length; i++ ){
var questionCount = 0;
for(var j = 0; j < service.categories[i].questions.length; j++ ) {
if (service.categories[i].questions[j].value != '' && service.categories[i].questions[j].value != undefined) {
questionCount++;
}
}
console.log(service.categories[i].name, ' # of quesitons: ', questionCount);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Categories

Resources