merge 2 array into new array after matching their content javascript - javascript

I have 2 arrays, and I want a new array based upon condition that the content of these 2 arrays matched
arr1 = [{
package_id: 'aabbccdd',
level: 2
},
{
package_id: 'xycd21',
level: 3
}
]
arr2 = [{
package_id: 'aabbccdd',
level: 1
},
{
package_id: 'zcb21',
level: 5
}]
mergedArray = [{
package_id: 'aabbccdd',
arr1Level: 2,
arr2Level: 1
},
{
package_id: 'xycd21',
arr1Level: 3,
arr2Level: 0
},
{
package_id: 'zcb21',
arr1Level: 0,
arr2Level: 5
}]
So if package_id is to be checked in both arrays. And if found in either array, new array pushed one element where level from both array is mentioned against package_id.
I just could not figure out the logic to do that. If that can be done by lodash kindly tell me.

You can easily solve this using loops like i did here:
var arr1 = [{
package_id: 'aabbccdd',
level: 2
},
{
package_id: 'xycd21',
level: 3
}
];
var arr2 = [{
package_id: 'aabbccdd',
level: 1
},
{
package_id: 'zcb21',
level: 5
}
];
var mergedArr = [];
var tempObj = {};
for(var i = 0; i < arr1.length; i++){
tempObj.package_id = arr1[i].package_id;
tempObj.arr1Level = arr1[i].level;
tempObj.arr2Level = 0;
for(var k = 0; k < arr2.length; k++){
if(arr1[i].package_id === arr2[k].package_id){
tempObj.arr2Level = arr2[k].level;
}
}
mergedArr.push(tempObj);
tempObj = {};
}
for(i = 0; i < arr2.length; i++){
var isNew = true;
for(k = 0; k < mergedArr.length; k++){
if(arr2[i].package_id === mergedArr[k].package_id){
isNew = false;
}
}
if(isNew){
tempObj.package_id = arr2[i].package_id;
tempObj.arr2Level = arr2[i].level;
tempObj.arr1Level = 0;
mergedArr.push(tempObj);
tempObj = {};
}
}
console.log(mergedArr);

You can first add both arrays to one array and then use reduce() and forEach() to create new array of objects. Also you can use another object to group elements by package_id
var arr1 = [{ package_id: 'aabbccdd', level: 2 }, { package_id: 'xycd21', level: 3 }];
var arr2 = [{ package_id: 'aabbccdd', level: 1 }, { package_id: 'zcb21', level: 5 }];
var o = {}
var arrays = [arr1, arr2]
var keys = Array.from(Array(arrays.length), (e, i) => ({['arr' + (i + 1) + 'Level']: 0}))
var result = arrays.reduce(function(r, a, i) {
a.forEach(function(e) {
if (!o[e.package_id]) {
o[e.package_id] = Object.assign({}, {package_id: e.package_id}, ...keys)
r.push(o[e.package_id]);
}
o[e.package_id]['arr' + (i + 1) + 'Level'] = e.level;
})
return r;
}, [])
console.log(result)

You could use a structure approach with dynamic keys for different arrays and use the keys as help for generating default values.
var arr1 = [{ package_id: 'aabbccdd', level: 2 }, { package_id: 'xycd21', level: 3 }],
arr2 = [{ package_id: 'aabbccdd', level: 1 }, { package_id: 'zcb21', level: 5 }],
keys = [{ level: 'arr1level' }, { level: 'arr2level' }],
result = [arr1, arr2].reduce(function (hash) {
return function (r, a, i) {
a.forEach(function (b) {
if (!hash[b.package_id]) {
hash[b.package_id] = { package_id: b.package_id },
r.push(hash[b.package_id]);
}
keys.forEach(function (key) {
Object.keys(key).forEach(function (k) {
hash[b.package_id][key[k]] = 0;
});
});
Object.keys(b).forEach(function (k) {
var key = keys[i][k] || k;
hash[b.package_id][key] = b[k];
});
});
return r;
};
}(Object.create(null)), []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related

count occurrences of items in an array from an nested items in an array of objects javascript

I have this array of dates.
const dateArray = ["7/12/2021","7/13/2021","7/14/2021","7/15/2021"]
and I am trying to see if any of these dates appear inside my other array of array of objects, those dates will match something inside the objects.
const data = [
[ { id: 1, date: "7/13/2021" }, { id:2, date: "7/15/2021" } ],
[ { id: 1, date: "7/14/2021" }, { id:2, date: "7/15/2021" } ],
]
so if date doesn't match I want to return 0 for that date. something like this
const result = [
[0, 1, 0, 1],
[0, 0, 1, 1]
]
I tried something like this.....
var getResult = (dateArray, data) => {
const result = []
let index = 0;
for (let i = 0; i < dateArray.length; i++) {
for (let j = 0; j < data.length; j++) {
let count = 0
if (dateArray[i] === data[j][index].date) {
count++
index++
if (index === data[i].length) {
return
}
}
result.push(count)
}
}
console.log(result)
}
but it doesn't work of course....
Thank you for your help!
const
dateArray = ["7/12/2021","7/13/2021","7/14/2021","7/15/2021"],
data = [
[ { id: 1, date: "7/13/2021" }, { id:2, date: "7/15/2021" } ],
[ { id: 1, date: "7/14/2021" }, { id:2, date: "7/15/2021" } ],
];
// iterate over data
const result = data.map(arr => {
// get occurences count of current array dates
const occurences = arr.reduce((map, {date}) =>
map.set(date, (map.get(data) || 0) + 1)
, new Map);
// return list of occurences for dateArray elements
return dateArray.map(date => occurences.get(date) || 0);
}, []);
console.log(result);
You can do something like this
const dateArray = ["7/12/2021", "7/13/2021", "7/14/2021", "7/15/2021"];
const data = [
[{
id: 1,
date: "7/13/2021"
}, {
id: 2,
date: "7/15/2021"
}],
[{
id: 1,
date: "7/14/2021"
}, {
id: 2,
date: "7/15/2021"
}],
];
const result = data.map(item => {
const resArr = (new Array(dateArray.length)).fill(0);
item.forEach(entity => {
const index = dateArray.findIndex(dateItem => dateItem == entity.date);
if (index >= 0) {
resArr[index]++;
}
});
return resArr;
});
console.log(result);

Set.add only add in 1 item [duplicate]

This question already has answers here:
How to add an array of values to a Set
(11 answers)
Closed 3 years ago.
Set only adds 1 copy of an array and I'm not sure why it doesn't keep adding other copies.
The function below takes in an array of trips with the travelers id and another array containing the travelers' ids and names. In this chunk of code,
if(item.type === type){
store.add(...item.travelers);
}
I expected that 123,456 and 789 will be added to the set. However, only 123 and 456 are added. Why doesn't the Set add in the second copy (which would be 456 and 789)?
const travelers = [
{
id: 123,
name: 'John'
},
{
id: 456,
name: 'Raymond'
},
{
id: 789,
name: 'Mary'
},
];
const trip = [
{
type: 'car',
travelers: [123, 456]
},
{
type: 'flight',
travelers: []
},
{
type: 'car',
travelers: [456, 789]
},
];
function determinePeopleForEachTripType(arr, travelers, type){
const result = [];
let store = new Set();
for(let i = 0; i< arr.length; i++){
let item = arr[i];
if(item.type === type){
store.add(...item.travelers);
}
}
store.forEach(eachStore =>{
for(let j = 0; j< travelers.length; j++){
if(eachStore === travelers[j].id){
result.push(travelers[j].name)
}
}
})
return result;
}
determinePeopleForEachTripType(trip, travelers, 'car');
Expected result: Set contains [123, 456, 789]. But actual output is Set contains [123, 456]. What are some possible ways to fix this code?
Set.prototype.add only takes one argument, and that's the one element - you need to iterate through travellers and add each item separately:
item.travelers.forEach(Set.prototype.add, store);
const travelers = [
{
id: 123,
name: 'John'
},
{
id: 456,
name: 'Raymond'
},
{
id: 789,
name: 'Mary'
},
];
const trip = [
{
type: 'car',
travelers: [123, 456]
},
{
type: 'flight',
travelers: []
},
{
type: 'car',
travelers: [456, 789]
},
];
function determinePeopleForEachTripType(arr, travelers, type){
const result = [];
let store = new Set();
for(let i = 0; i< arr.length; i++){
let item = arr[i];
if(item.type === type){
for (let traveler of item.travelers) {
store.add(traveler);
}
}
}
store.forEach(eachStore =>{
for(let j = 0; j< travelers.length; j++){
if(eachStore === travelers[j].id){
result.push(travelers[j].name)
}
}
})
return result;
}
const result = determinePeopleForEachTripType(trip, travelers, 'car');
console.log(result)

How to get array of arrays by grouping ids

I have an array:
let ar = [{
asst: 1,
v: 'b'
}, {
emp: 4
}, {
journal_id: 3
}, {
asst: 4
}, {
asst: 1,
v: 'a'
}, {
asst: 1,
v: 'c'
}, {
journal_id: 3
}, {
journal_id: 3
}]
I want an array that has asst and journal_id as array of arrays and emp as just an object in the array that has array of asst and journal_id.
Like this:
[[{asst:1, v: 'a'}, {asst:1, v: 'b'},{asst:1, v: 'c'}], [{asst:4}], [{journal_id:3}, {journal_id:3}, {journal_id:3}], {emp:4}]
I have tried this:
let ar = [{
asst: 1,
v: 'b'
}, {
emp: 4
}, {
journal_id: 3
}, {
asst: 4
}, {
asst: 1,
v: 'a'
}, {
asst: 1,
v: 'c'
}, {
journal_id: 3
}, {
journal_id: 3
}]
let asstArray = [],
journalArray = [],
fullArray = [];
for (let i = 0; i < ar.length; i++) {
debugger
if (ar[i].asst) {
let contains = false;
for (let j = 0; j < asstArray.length; j++) {
for (let k = 0; k < asstArray[j].length; k++) {
if (asstArray[j][k].asst == ar[i].asst) {
contains = true;
let d = asstArray[j][k];
}
}
if (contains) {
asstArray[j].push(ar[i]);
}
}
if (!contains) {
asstArray.push([ar[i]]);
}
} else if (ar[i].journal_id) {
let contains = false;
for (let j = 0; j < journalArray.length; j++) {
for (let k = 0; k < journalArray[j].length; k++) {
if (journalArray[j][k].journal_id == ar[i].journal_id) {
contains = true;
}
}
if (contains) {
journalArray[j].push(ar[i]);
}
}
if (!contains) {
journalArray.push([ar[i]]);
}
}
}
fullArray.push(asstArray);
fullArray.push(journalArray);
console.log(fullArray, "Full")
JS Fiddle
Here is a succint way to do it with reduce and Object.values. Also, the keys to check are declared in the initial value to the reduce function.
By using ES6 desctructuring, you can then rebuild the array you want at the end, with emp, out of the inner arrays.
With emp in the array:
const ar = [
{ asst: 1, v: 'b' },
{ emp: 4 },
{ journal_id: 3 },
{ asst: 4 },
{ asst: 1, v: 'a' },
{ asst: 1, v: 'c' },
{ journal_id: 3 },
{ journal_id: 3 }
];
const result = Object.values(ar.reduce((accum, e) => {
Object.keys(accum).forEach(k => {
if (k in e) accum[k].push(e);
});
return accum;
}, { asst: [], journal_id: [], emp: [] }));
console.log(result);
With emp outside the inner array:
const ar = [
{ asst: 1, v: 'b' },
{ emp: 4 },
{ journal_id: 3 },
{ asst: 4 },
{ asst: 1, v: 'a' },
{ asst: 1, v: 'c' },
{ journal_id: 3 },
{ journal_id: 3 }
];
let result = ar.reduce((accum, e) => {
Object.keys(accum).forEach(k => {
if (k in e) accum[k].push(e);
});
return accum;
}, { asst: [], journal_id: [], emp: [] });
const { emp, ...otherProps } = result;
result = [...Object.values(otherProps), emp[0]];
console.log(result);
You could combine the values of the wanted grouping keys to a single key and group by this value.
Objects without grouping keys are pushed to the result set directly.
var array = [{ asst: 1, v: 'b' }, { emp: 4 }, { journal_id: 3 }, { asst: 4 }, { asst: 1, v: 'a' }, { asst: 1, v: 'c' }, { journal_id: 3 }, { journal_id: 3 }], keys = ['asst', 'journal_id'],
keys = ['asst', 'journal_id'],
result = array.reduce((hash => (r, o) => {
if (keys.some(k => k in o)) {
var key = keys.map(k => o[k]).join('|');
if (!hash[key]) {
r.push(hash[key] = []);
}
hash[key].push(o);
} else {
r.push(o);
}
return r;
})({}), []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can reduce the array in a Map and then create a new array with the Map values:
const data = [{"asst":1,"v":"b"},{"emp":4},{"journal_id":3},{"asst":4},{"asst":1,"v":"a"},{"asst":1,"v":"c"},{"journal_id":3},{"journal_id":3}];
const grouped = data.reduce(
(result,item)=>{
//key is item.asst or item.jornal_id or other
const key = item.asst || item.journal_id || 'other';
//set result(key) with empty array or existing array and conat new item
return result.set(key,(result.get(key)||[]).concat(item));
},new Map()
);
//get other values or empty array if they don't exist:
const others = grouped.get('other') || [];
//remove others if they exist:
grouped.delete('other');
//log array from Map values
console.log(others.concat([...grouped.values()]));

Adding values from objects in an array

I have an array of objects:
var array = [{
id: "cards",
amount: 5
}, {
id: "shirts",
amount: 3
}, {
id: "cards",
amount: 2
}, {
id: "shirts",
amount: 3
}]
What I need to do is loop through this array and find the total of all id types.
So in this example, I would find the total amount of cards and shirts.
I'm not sure how to do this with objects. I've tried stripping the objects down with Object.values(array), but is there a way to do it with the objects?
Thanks for your help.
This should do what you want:
var array = [
{ id: "cards", amount: 5 },
{ id: "shirts", amount: 3 },
{ id: "cards", amount: 2 },
{ id: "shirts", amount: 3 }
];
var result = array.reduce(function(entities, item) {
entities[item.id] = (entities[item.id] || 0) + item.amount;
return entities;
}, {})
console.log(result);
You would loop your array, check the id property for your target object, then enumerate and outer scope variable with the value stored in the amount property.
var totalShirts = 0;
var totalCards = 0;
for(var i = 0, len = array.length; i < len; i++){
var entry = array[i];
if(entry.id === "cards"){
totalCards += entry.amount;
}
else if(entry.id === "shirts"){
totalShirts += entry.amount;
}
}
console.log("Total Cards: " + totalCards);
console.log("Total Shirts: " + totalShirts);
Here is an example that gets the total of each item
var array = [{id:"cards", amount: 5}, {id:"shirts", amount: 3}, {id:"cards", amount: 2}, {id:"shirts", amount: 3}];
var result = array.reduce(function(accumulator, current) {
if (!(current.id in accumulator)) {
accumulator[current.id] = current.amount;
} else {
accumulator[current.id] += current.amount;
}
return accumulator;
}, {});
console.log(result);
A simple forEach will do the trick:
var counts = {}
array.forEach(v => {
counts[v.id] = (counts[v.id] || 0) + v.amount
})
console.log(counts)
will print:
{
cards: 7
shirts: 6
}
Here is a O(n) time solution.
var totals = new Object();
for(var i = 0;i < array.length;i ++) {
var id = array[i].id;
var amount = array[i].amount;
if(totals[id] == undefined) {
totals[id] = amount;
} else {
totals[id] += amount;
}
}
console.log(totals);
You can use for..of loop
var array = [{
id: "cards",
amount: 5
}, {
id: "shirts",
amount: 3
}, {
id: "cards",
amount: 2
}, {
id: "shirts",
amount: 3
}]
let res = {};
for (let {id,amount} of array) {
if (!res.hasOwnProperty(id)) res[id] = 0;
res[id] += amount;
}
console.log(res);
Use a for-loop to do this:
var totalCards = 0;
var totalShirt = 0;
for (var i = 0; i < arr.length; i++) {
if (arr[i].id === "cards") {
totalCards += arr[i].amount;
} else {
totalShirt += arr[i].amount;
}
}
Do the magic in for loop. This example should be general enough:
var array = [ {id:"cards", amount: 5}, {id:"shirts", amount: 3}, {id:"cards", amount: 2}, {id:"shirts", amount: 3} ];
var output = [];
for(var i of array) {
if(!output[i.id]) {
output[i.id] = 0;
}
output[i.id] += i.amount;
}
console.log(output);
var array = [{id:"cards", amount: 5}, {id:"shirts", amount: 3}, {id:"cards", amount: 2}, {id:"shirts", amount: 3}];
var arr = [];
array.forEach(v => arr.push(v.id));
var newArr = [...new Set(arr)];
var arr2 = [];
newArr.forEach(function(v) {
var obj = {};
obj.id = v;
obj.counter = 0;
arr2.push(obj);
});
arr2.forEach(v => array.forEach(c => c.id == v.id ? v.counter += c.amount : v));
console.log(arr2);
You can use Array.forEach() to iterate over each element of the array. The total object is an associative array where the index is the id field of array element objects.
var array = [{ id: "cards", amount: 5 },
{ id: "shirts", amount: 3 },
{ id: "cards", amount: 2},
{ id: "shirts", amount: 3 }];
var total = {};
array.forEach(function (el) {
if (total[el.id]) {
total[el.id] += el.amount
} else {
total[el.id] = el.amount
}
});
console.log(JSON.stringify(total));
You could use Array#reduce and sum the amount.
var array = [{ id: "cards", amount: 5 }, { id: "shirts", amount: 3 }, { id: "cards", amount: 2 }, { id: "shirts", amount: 3 }],
result = array.reduce(function (r, a) {
r[a.id] = (r[a.id] || 0) + a.amount;
return r;
}, {});
console.log(result);
You can use this code
if (!Object.keys) {
Object.keys = function (obj) {
var keys = [],
k;
for (k in obj) {
if (Object.prototype.hasOwnProperty.call(obj, k)) {
keys.push(k);
}
}
return keys;
};
}
then you can do this in older browsers as well:
var len = Object.keys(obj).length;

Merge arrays in JS

Suppose I have the following arrays:
var first = [
{ id: 1, name: 'first' },
{ id: 2, name: 'second' },
{ id: 3, name: 'third' }
]
var second = [
{ id: 2, field: 'foo2' },
{ id: 3, field: 'foo3' },
{ id: 4, field: 'foo4' }
]
var third = [
{ id: 2, data: 'some2' },
{ id: 5, data: 'some5' },
{ id: 6, data: 'some6' }
]
I want to merge them to get the following result:
var result = [
{ id: 1, name: 'first', field: undefined, data: undefined },
{ id: 2, name: 'second', field: 'foo2', data: 'some2' },
{ id: 3, name: 'third', field: 'foo3', data: undefined },
{ id: 4, name: undefined, field: 'foo4', data: undefined },
{ id: 5, name: undefined, field: undefined, data: 'some5' },
{ id: 6, name: undefined, field: undefined, data: 'some6' }
]
How could I do it with JavaScript?
You should get all existed keys and after create new Objects with fill "empty" keys:
function mergeArrays(){
var keys = {};
//save all existed keys
for(var i=arguments.length;--i;){
for(var j=arguments[i].length;--j;){
for(var key in arguments[i][j]){
keys[key] = true;
}
}
}
var res = [];
for(var i=arguments.length;--i;){
for(var j=arguments[i].length;--j;){
//set clone of object
var clone = JSON.parse(JSON.stringify(arguments[i][j]));
for(var key in keys){
if(!(key in clone)){
clone[key] = undefined;
}
}
res.push(clone);
}
}
return res;
}
https://jsfiddle.net/x3b0tk3g/
There is no simple solution for what you want. Here is my suggestion.
var first = [
{ id: 1, name: 'first' },
{ id: 2, name: 'second' },
{ id: 3, name: 'third' }
]
var second = [
{ id: 2, filed: 'foo2' },
{ id: 3, field: 'foo3' },
{ id: 4, field: 'foo4' }
];
var third = [
{ id: 2, data: 'some2' },
{ id: 4, data: 'some4' },
{ id: 6, data: 'some6' }
];
var result = {};
first.concat(second,third).forEach(function(item){
var id = item.id;
var row = result[id];
if(!row){
result[id] = item;
return;
}
for(var column in item){
row[column] = item[column];
}
});
var finalResult = Object.keys(result).map(function(id){
return result[id];
});
console.log(finalResult);
fiddle: http://jsfiddle.net/bs20jvnj/2/
function getByProperty(arr, propName, propValue) {
for (var i = 0; i < arr.length; i++) {
if (arr[i][propName] == propValue) return arr[i];
}
}
var limit = first.length + second.length + third.length;
var res = [];
for (var i = 1; i < limit; i++) {
var x = $.extend({}, getByProperty(first, "id", i), getByProperty(second, "id", i), getByProperty(third, "id", i));
console.log(x["id"]);
if (x["id"] === undefined) x["id"] = i;
res.push(x);
}
console.log(res);
There's probably a shorter way to solve this, but this covers all the steps, including ensuring that there are default properties that are undefined if not found. It also takes any number of input arrays, and you can specify what default keys you require if they're not already covered by the keys in the existing objects, so pretty future-proof for your needs.
// merges the key/values of two objects
function merge(a, b) {
var key;
if (a && b) {
for (key in b) {
if (b.hasOwnProperty(key)) {
a[key] = b[key];
}
}
}
return a;
}
function concatenate() {
var result = [];
var args = arguments[0];
for (var i = 0, l = args.length; i < l; i++) {
result = result.concat(args[i]);
}
return result;
}
// return a default object
function getDefault() {
return {
id: undefined,
name: undefined,
data: undefined,
field: undefined
};
}
// loop over the array and check the id. Add the id as a key to
// a temporary pre-filled default object if the key
// doesn't exist, otherwise merge the existing object and the
// new object
function createMergedArray(result) {
var temp = {};
var out = [];
for (var i = 0, l = result.length; i < l; i++) {
var id = result[i].id;
if (!temp[id]) temp[id] = getDefault();
merge(temp[id], result[i]);
}
// loop over the temporary object pushing the values
// into an output array, and return the array
for (var p in temp) {
out.push(temp[p]);
}
return out;
}
function mergeAll() {
// first concatenate the objects into a single array
// and then return the results of merging that array
return createMergedArray(concatenate(arguments));
}
mergeAll(first, second, third);
DEMO

Categories