How to merge multiple array in JavaScript? - javascript

I have multiple arrays and I want to merge the data of all the array into one array of objects .
All the data will be merged on the basis of the key so how to make one production level code so that it will merge all the data.
results[0]=
[ {categoryGroupID: '1231',categoryID: '12311',categoryName: 'External'},
{categoryGroupID: '1231',categoryID: '12312',categoryName: 'Internal'},
{categoryGroupID: '1231',categoryID: '141414141',categoryName: ''},
{categoryGroupID: '1232',categoryID: '12321',categoryName: 'Style'},
{categoryGroupID: '1233',categoryID: '123222',categoryName: ''},
{categoryGroupID: '1233',categoryID: '12331',categoryName: 'Customer Satisfaction'}]
results[1]=
[ { categoryGroupID: '1231',categoryGroupName: 'Store ambience'},
{ categoryGroupID: '1232',categoryGroupName: 'Communication'},
{categoryGroupID: '1233',categoryGroupName: 'Overall Satisfaction'},
{categoryGroupID: '12331',categoryGroupName: null}]
results[2]=
[ {categoryID: '12311',questionID: '12311111',questionName: 'tell me snything'},
{categoryID: '12312',questionID: '12311113',questionName: 'whatever'},
{categoryID: '12311',questionID: '123ques',questionName: 'ashjsh'},
{categoryID: '12311',questionID: '123test',questionName: null}]
results[3]=
[ { questionID: '12311113',choiceID: '1231111111',choiceValue: 'good'},
{ questionID: '12311113',choiceID: '1231111112',choiceValue: 'very good'},
{questionID: '12311113',choiceID: '12311113113',choiceValue: 'bad'}]
MY output should like this so how to do it
"categoryGroup":
[
{"categoryGroupID": "1231","categoryGroupName": "Store ambience",
"category": [
{"categoryID": "12312","categoryName": "Internal",
"question": [
{"questionID": "12311113","questionName": "whatever",
"choice": [
{"choiceID": "1231111111","choiceValue": "good"},
{"choiceID": "1231111112","choiceValue": "very good"},
{"choiceID": "12311113113","choiceValue": "bad",}
],
}]
},
{"categoryID": "12311","categoryName": "External",
"question": [
{"questionID": "12311111","questionName": "tell me snything",},
{"questionID": "123ques","questionName": "ashjsh",},
{"questionID": "123test","questionName": null,}
]},
{"categoryID": "141414141","categoryName": "",}]
},
{"categoryGroupID": "1232","categoryGroupName": "Communication",
"category": [
{"categoryID": "12321","categoryName": "Style"}]
},
{"categoryGroupID": "1233","categoryGroupName": "Overall Satisfaction",
"category": [
{"categoryID": "123222","categoryName": "",},
{"categoryID": "12331","categoryName": "Customer Satisfaction",}]
},
{"categoryGroupID": "12331","categoryGroupName": null}
]

Without going into the depths of all this and how you will pretty much need to manually handle all cases here is an example of how it can work (probably not should work).
This is based on the indexes (0, 1, 2, 3) of results will always be the same and employs the filter and map Array functions. For performance I am not sure how well this will work in a large scenario.
var results = {};
results[0] =
[{ categoryGroupID: '1231', categoryID: '12311', categoryName: 'External' },
{ categoryGroupID: '1231', categoryID: '12312', categoryName: 'Internal' },
{ categoryGroupID: '1231', categoryID: '141414141', categoryName: '' },
{ categoryGroupID: '1232', categoryID: '12321', categoryName: 'Style' },
{ categoryGroupID: '1233', categoryID: '123222', categoryName: '' },
{ categoryGroupID: '1233', categoryID: '12331', categoryName: 'Customer Satisfaction' }];
results[1] =
[{ categoryGroupID: '1231', categoryGroupName: 'Store ambience' },
{ categoryGroupID: '1232', categoryGroupName: 'Communication' },
{ categoryGroupID: '1233', categoryGroupName: 'Overall Satisfaction' },
{ categoryGroupID: '12331', categoryGroupName: null }];
results[2] =
[{ categoryID: '12311', questionID: '12311111', questionName: 'tell me snything' },
{ categoryID: '12312', questionID: '12311113', questionName: 'whatever' },
{ categoryID: '12311', questionID: '123ques', questionName: 'ashjsh' },
{ categoryID: '12311', questionID: '123test', questionName: null }];
results[3] =
[{ questionID: '12311113', choiceID: '1231111111', choiceValue: 'good' },
{ questionID: '12311113', choiceID: '1231111112', choiceValue: 'very good' },
{ questionID: '12311113', choiceID: '12311113113', choiceValue: 'bad' }];
var o = {
categoryGroup: results[1].map(function (categoryGroup) {
var categoryGroup = {
categoryGroupID: categoryGroup.categoryGroupID,
categoryGroupName: categoryGroup.categoryGroupName
};
categoryGroup['category'] = results[0].filter(function (item) { return item.categoryGroupID == categoryGroup.categoryGroupID })
.map(function (item) {
return {
categoryId: item.categoryID,
categoryName: item.categoryName,
question: results[2].filter(function (ques) { return ques.categoryID == item.categoryID })
.map(function (ques) {
return {
questionId: ques.questionID,
questionName: ques.questionName,
choice: results[3].filter(function (ch) { return ch.questionID == ques.questionID })
.map(function (ch) {
return {
choiceID: ch.choiceID,
choiceValue: ch.choiceValue
}
})
}
})
};
});
return categoryGroup;
})
};
console.log(o);

See this -> How to merge two arrays in Javascript and de-duplicate items
var array1 = ["1","2"];
var array2 = ["3", "4"];
var array3 = array1.concat(array2); // Merges both arrays
// [ '1', '2', '3', '4' ]
for the Apache Commons Lang Array Utils see this -> How can I concatenate two arrays in Java?
js versions are dojo http://dojotoolkit.org/reference-guide/1.10/dojo/_base/array.html and util-array https://www.npmjs.com/package/util-array
This is another dojo example http://dojo-toolkit.33424.n3.nabble.com/How-to-concatenate-arrays-in-Dojo-td3744293.html
http://wiki.servicenow.com/index.php?title=ArrayUtil

Related

Can I sort an array of objects based on a array of subarrays?

I would ask a question regarding sorting.
Let's say I have an array of objects:
let arrayToBeSorted = [
{
name:"name1",
id:"id1",
},
{
name:"name2",
id:"id2",
},
{
name:"name3",
id:"id3",
},
{
name:"name4",
id:"id4",
},
{
name:"name5",
id:"id5",
},
{
name:"name6",
id:"id6",
}];
And Let's say I have an array of sub arrays which each one is containing IDs string like that:
let sortArray = [["id2", "id1"], ["id5"], ["id6","id3","id4"]]
What I want to do is to sort the arrayToBeSorted based on the sortArray preserving each subarrays (in order to maintain an hermetic order)
This is the wanted result:
arrayToBeSorted = [
{
name:"name2",
id:"id2",
},
{
name:"name1",
id:"id1",
},
{
name:"name5",
id:"id5",
},
{
name:"name6",
id:"id6",
},
{
name:"name3",
id:"id3",
},
{
name:"name4",
id:"id4",
}];
EDIT: I tried to:
arrayToBeSorted.sort((a,b)=> for(var i=0; i<sortArray.length;i++)
{
sortArr.indexOf(a.item.id) - sortArr.indexOf(b.item.id)
});
I also thought of sorting by each array and the concat the sorted result, but no success...
Thanks!
You seem to be overcomplicating the sort operation here. Use sort() on arrayToBeSorted and get the indexOf each array element in a flat()tened copy of sortArray:
let arrayToBeSorted = [{
name: "name1",
id: "id1",
}, {
name: "name2",
id: "id2",
}, {
name: "name3",
id: "id3",
}, {
name: "name4",
id: "id4",
}, {
name: "name5",
id: "id5",
}, {
name: "name6",
id: "id6",
}];
let sortArray = [
["id2", "id1"],
["id5"],
["id6", "id3", "id4"]
];
console.log(arrayToBeSorted.sort((a, b) => sortArray.flat().indexOf(a.id) - sortArray.flat().indexOf(b.id)));
You could flat the array and build an object with wanted order and sort the array.
const
data = [{ name: "name1", id: "id1" }, { name: "name2", id: "id2" }, { name: "name3", id: "id3" }, { name: "name4", id: "id4" }, { name: "name5", id: "id5" }, { name: "name6", id: "id6" }],
sortArray = [["id2", "id1"], ["id5"], ["id6", "id3", "id4"]],
order = Object.fromEntries(sortArray.flat().map((k, i) => [k, i + 1]));
data.sort((a, b) => order[a.id] - order[b.id]);
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use sort() based on a flattened sortArray using findIndex() or indexOf() as #esqew. You could also go a step further and pre-process sortArray and create an object ids as keys and indices of sortArray as values. Then the sort function would be based on the object as follows:
let arrayToBeSorted = [{
name: "name1",
id: "id1",
},
{
name: "name2",
id: "id2",
},
{
name: "name3",
id: "id3",
},
{
name: "name4",
id: "id4",
},
{
name: "name5",
id: "id5",
},
{
name: "name6",
id: "id6",
}
];
let sortArray = [["id2", "id1"], ["id5"], ["id6","id3","id4"]];
const flatO = Object.fromEntries( sortArray.flat().map((id,i) => [id,i]) );
const sortedArray = arrayToBeSorted.sort((a,b) => flatO[a.id] - flatO[b.id]);
console.log( sortedArray );
NOTE: This is equivalent to #NinaScholz's solution. Saw it just after I posted this. I have upvoted both #NinaScholz's and #esqew's solutions but I would take #NinaScholz's since the flat() method including the creation of the order object execute JUST ONCE.

How to generate a chain of indexes for element in nested array? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
I have object with subCategories property that contains objects where each contains subCategories as well.
const category = {
categoryId: 123,
name: "Cars",
subCategories: [
{ categoryId: 32112, name: "BMW", subCategories: [] },
{
categoryId: 12321,
name: "Audi",
subCategories: [
{
categoryId: 21312,
name: "Audi engine",
subCategories: [
{ categoryId: 1212, name: "engine-V-123", subCategories: [] },
],
},
{ categoryId: 21112, name: "Audi wheels", subCategories: [] },
],
},
{...},
{...}
],
}
I need to write a function that will return a chain of indexes. For example, if I want to get engine-V-123 engine with id 1212, I should get:
".subCategories[1].subCategories[0].subCategories[0]"
Recursively generate path index by value from object.
const category = { categoryId: 123, name: "Cars", subCategories: [{ categoryId: 32112, name: "BMW", subCategories: [] }, { categoryId: 12321, name: "Audi", subCategories: [{ categoryId: 21312, name: "Audi engine", subCategories: [{ categoryId: 1212, name: "engine-V-123", subCategories: [] },], }, { categoryId: 21112, name: "Audi wheels", subCategories: [] },], },], }
function* extractPaths(data, value, path = "") {
for (const key in data) {
let $data = data[key], index = isFinite(+key) ? `[${key}]` : "." + key
if (typeof $data == "object")
yield* extractPaths($data, value, path + index);
else if (value == $data)
yield path
}
}
console.log([...extractPaths(category, "engine-V-123")]);
Is this what you want?
const arr = [
{
categoryId: 1,
name: "Cars",
subCategories: [
{ categoryId: 21, name: "BMW", subCategories: [] },
{
categoryId: 22,
name: "Audi",
subCategories: [
{
categoryId: 31,
name: "Audi engine",
subCategories: [
{ categoryId: 41, name: "engine-V-123", subCategories: [] },
],
},
{ categoryId: 32, name: "Audi wheels", subCategories: [] },
],
},
],
},
];
let isCategoryFound = false;
function searchIndex(arr, categoryId, name) {
for (let i = 0; i < arr.length; i++) {
let res = "";
res += `.subCategories[${i}]`;
const index = arr.findIndex(
el => el.categoryId === categoryId && el.name === name
);
if (index !== -1) {
isCategoryFound = true;
// return res;
} else {
res += searchIndex(arr[i].subCategories, categoryId, name);
}
if (isCategoryFound) {
return res;
}
}
return "";
}
const output = searchIndex(arr, 41, "engine-V-123");
console.log(output);

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 groupBy array of objects based on properties in vanilla javascript

How do you groupBy array of objects based on specific properties in vanilla javascript? For example this given:
const products = [
{
category: "Sporting Goods",
price: "$49.99",
stocked: true,
name: "Football"
},
{
category: "Sporting Goods",
price: "$9.99",
stocked: true,
name: "Baseball"
},
{
category: "Sporting Goods",
price: "$29.99",
stocked: false,
name: "Basketball"
},
{
category: "Electronics",
price: "$99.99",
stocked: true,
name: "iPod Touch"
},
{
category: "Electronics",
price: "$399.99",
stocked: false,
name: "iPhone 5"
},
{ category: "Electronics", price: "$199.99", stocked: true, name: "Nexus 7" }
];
i want to run a reduce function that would result to a new array of objects like this:
Intended Output:
const categorize = [
{
category:"Sporting Goods",
products: [
{
name:"Football",
price: "$49.99",
stocked: true
},
{
name:"Baseball",
price: "$9.99",
stocked: true
},
{
name:"Basketball",
price: "$29.99",
stocked: true
}
]
},
{
category: "Electronics",
products: [
{
name: "iPod Touch",
price: "$99.99",
stocked: true
},
{
name: "iPhone 5",
price: "$399.99",
stocked: false
},
{
name: "Nexus 7",
price: "$199.99",
stocked: true
}
]
}
]
i based my solution from the tutorial here: https://www.consolelog.io/group-by-in-javascript/ using the reduce function.
Here's my code:
const groupBy = (arr,prop)=>{
return arr.reduce((groups,item)=>{
let val = item[prop];
groups[val] = groups[val]||[];
groups[val].push(item);
return groups
},{});
}
const categorize = groupBy(products,'category');
console.log(categorize);
/* returns an Object like
Object {Sporting Goods: Array[3], Electronics: Array[3]}
however it's not the intended output.
*/
I tried to return Object.values(obj) or Object.entries(obj) inside the groupBy function but it just returns an array of 2 arrays like [Array[3],Array[3]] and if i set the initial value (2nd parameter of reduce) to empty [] instead of {}, the output is just an empty array. Need help, thanks!
Because you want an array containing objects (rather than just an array of plain values), create a { category, products: [] } object if it doesn't exist in the accumulator:
const products=[{category:"Sporting Goods",price:"$49.99",stocked:!0,name:"Football"},{category:"Sporting Goods",price:"$9.99",stocked:!0,name:"Baseball"},{category:"Sporting Goods",price:"$29.99",stocked:!1,name:"Basketball"},{category:"Electronics",price:"$99.99",stocked:!0,name:"iPod Touch"},{category:"Electronics",price:"$399.99",stocked:!1,name:"iPhone 5"},{category:"Electronics",price:"$199.99",stocked:!0,name:"Nexus 7"}];
const output = Object.values(
products.reduce((a, { category, ...item }) => {
if (!a[category]) {
a[category] = { category, products: [] };
}
a[category].products.push(item);
return a;
}, {})
);
console.log(output);
function (){
var map = {};
products.forEach((p) => {
if (map[p.category]) {
var c = p.category;
delete p.category;
map[c].push(p);
} else {
var c = p.category;
delete p.category;
map[c]=[c]
}
});
Object.keys(map).forEach((m) => {
ans.push({category:m, products: map[m]})
})
}
you can collect in one go products and map them.
Then make your resultinng array

Map value of an attribute in one object array to an attribute in another object array Javascript

I have two arrays of objects:
courses = [ { _id: 999, courseCode: "Eng1" },
{ _id: 777, courseCode: "Sci1" },
{ _id: 666, courseCode: "Eng2" },
{ _id: 888, courseCode: "Sci2" } ]
sectionCourses = [ { sectionCode: "1A", courseId: "999" },
{ sectionCode: "1A", courseId: "777" },
{ sectionCode: "2A", courseId: "666" },
{ sectionCode: "2A", courseId: "888" } ]
I want to filter the courses array in such a way that it contains only the courses that are not in a section.
For example if I select section with sectionCode: "2A", the courses array should only contain
courses = [ { _id: 999, courseCode: "Eng1" },
{ _id: 777, courseCode: "Sci1" },
{ _id: 888, courseCode: "Sci2" } ]
I tried to do this way:
courses = courses.filter(c => !(sectionCourses.includes(c._id)))
but I know this is incomplete because I can't figure out how to access courseId in sectionCourses.
Please help.
You can't use .includes() method to find the whole object by its _id, includes compares the whole objects and doesn't search for a specific property.
What you can do here is to get an array of courseIds to be ignored based on the sectionCode you provided, and then filter the courses that their _id doesn't exist in this array of ids:
function getCourses(catCode) {
var coursesIdstoIgnore = sectionCourses.filter(s => s.sectionCode === catCode).map(s => s.courseId);
return courses.filter(c => coursesIdstoIgnore.indexOf(c["_id"].toString()) == -1);
}
Demo:
var courses = [{
_id: 999,
courseCode: "Eng1"
},
{
_id: 777,
courseCode: "Sci1"
},
{
_id: 666,
courseCode: "Eng2"
},
{
_id: 888,
courseCode: "Sci2"
}
];
var sectionCourses = [{
sectionCode: "1A",
courseId: "999"
},
{
sectionCode: "1A",
courseId: "777"
},
{
sectionCode: "2A",
courseId: "666"
},
{
sectionCode: "2A",
courseId: "888"
}
];
function getCourses(catCode) {
var cousesIdstoIgnore = sectionCourses.filter(s => s.sectionCode === catCode).map(s => s.courseId);
console.log(cousesIdstoIgnore);
return courses.filter(c => cousesIdstoIgnore.indexOf(c["_id"].toString()) == -1);
}
var results = getCourses("2A");
console.log(results);
courses.filter(course => sectionCourses.find(section => +section.courseId === +course._id))
Note how i use the +operator before of the courseId and _id properties. this automatically turns a String typed number into a Number.
e.g
+"1" = 1
+1 = 1
This is very useful for slight comparison gotchas when using ===
Note Array.find() doesn't work with IE

Categories

Resources