Looping over two arrays in javascript simultaneously - javascript

let masterList=[{id:1,name:'Abc'},{id:2,name:'Def'},{id:3,name:'Ghi'}];
let selectedList=[2,3];
The desired result is to have
//desiredList=[{id:2,name:'Def'},{id:3,name:'Ghi'}]
Currently what I am doing is
let parsedArray = [];
masterList.forEach(mItem => {
selectedList.forEach(sItem => {
if (mItem.id === sItem) {
parsedArray.push(mItem);
}
});
});
desiredList=parsedArray
I do not find this method efficient when iterating over large arrays, is there any logic, any inbuilt javascript operators using which I can achieve the same?

You could take a map with id as key and the object as value and map the wanted values from the map by mapping selectedList.
This approach uses the order from selectedList.
var masterList = [{ id: 1, name: 'Abc' }, { id: 2, name: 'Def' }, { id: 3, name: 'Ghi' }],
selectedList = [2, 3],
result = selectedList.map(Map.prototype.get, new Map(masterList.map(o => [o.id, o])));
console.log(result);

It should be a simple filter on the masterList:
masterList.filter(item => selectedList.includes(item.id));

You can use Array filter() to do this.
Demo:
let masterList=[{id:1,name:'Abc'},{id:2,name:'Def'},{id:3,name:'Ghi'}];
let selectedList=[2,3];
let desiredList = masterList.filter((val) => selectedList.includes(val.id));
console.log(desiredList)

You can first convert selectedList to Set and then use filter() method array of objects.
You can use Set.prototype.has to check whether the id of the objects exists in the set or not. And this method has O(1) time-complexity. So the time-complexity of the whole algorithm will be linear.
let masterList=[{id:1,name:'Abc'},{id:2,name:'Def'},{id:3,name:'Ghi'}];
let selectedList = [2,3];
let set = new Set(selectedList);
let res = masterList.filter(x => set.has(x.id));
console.log(res)

Turn the first array into an object indexed by id first, so you can look up the appropriate matching object in O(1) time, and then you can .map the selectedList:
const masterList=[{id:1,name:'Abc'},{id:2,name:'Def'},{id:3,name:'Ghi'}];
const selectedList=[2,3];
const masterById = masterList.reduce((a, obj) => {
a[obj.id] = obj;
return a;
}, {});
const desiredList = selectedList.map(id => masterById[id]);
console.log(desiredList);

Try this:
let masterList=[{id:1,name:'Abc'},{id:2,name:'Def'},{id:3,name:'Ghi'}];
let selectedList=[2,3];
const result = masterList.filter(({id})=> selectedList.includes(id));
console.log(result);

Related

Filtering one object with another array's object key

I am trying to filter an object with another object inside of an array.
To be more precise, I am trying to compare the keys of the object inside the array, to the keys of my main object. If the values are the same, I want to return the value corresponding to those keys.
Here's an example:
var a = {
"maths":"A++",
"literature":"C-",
"sports":"B+",
"biology":"D",
"chemistry":"A",
"english":"A+",
"physics":"C+"
}
var b = [{
"maths":"Mathematics",
"biology":"Biology",
"physics":"Physics"
}]
I wanna check if any of the keys in object b are inside object a and if they are, I want to return their value into array. For example, I want to return ["A++","D","C+"]
I've tried using filter and Array.prototype.some but I couldn't figure out anything. Any advice on how should I achieve this?
First make an array or Set of all the keys inside b, then use .map to access each key on the a object:
var a = {
"maths":"A++",
"literature":"C-",
"sports":"B+",
"biology":"D",
"chemistry":"A",
"english":"A+",
"physics":"C+"
}
var b = [{
"maths":"Mathematics",
"biology":"Biology",
"physics":"Physics"
}];
const keys = b.flatMap(Object.keys);
const arr = keys.map(key => a[key]);
console.log(arr);
I'm assuming that you want to handle multiple objects in b.
If so and if you want one array for each object in b then you could do something like:
var a = {
"maths":"A++",
"literature":"C-",
"sports":"B+",
"biology":"D",
"chemistry":"A",
"english":"A+",
"physics":"C+"
}
var b = [{
"maths":"Mathematics",
"biology":"Biology",
"physics":"Physics"
},{
"maths":"Mathematics",
"biology":"Biology",
"english":"English"
}]
const result = b.map(obj => Object.keys(obj).map(key => a[key]));
console.log(result);
If you are dealing with a single object in the array b, then you can do this:
var a = {
"maths":"A++",
"literature":"C-",
"sports":"B+",
"biology":"D",
"chemistry":"A",
"english":"A+",
"physics":"C+"
}
var b = [{
"maths":"Mathematics",
"biology":"Biology",
"physics":"Physics"
}]
const valuesInAndB = Object.keys(a).reduce((acc,x) => {
if (b[0][x]) {
return acc.concat(a[x]);
}
return acc;
}, []);
console.log(valuesInAndB);
However, if the objects in b will be greater than one then as answered by #certainperformance you could get all the keys in b and map through a with those keys.
const keysInB = b.flatMap(Object.keys);
keysInB.map(key => a[key]);
flatMap is not available in some older browsers, please keep that in mind.

ES6 Merge two arrays (array contains another array inside) based on key Typescript or Javascript

I want to merge two arrays both array contains another array inside. refer below two arrays.
const arr1=
[{"projectId":30278,"projectName":null,"details":[{"amount":"9097457.11","currency":"USD","paymentDate":"2016-05-16T00:00:00"}]},{"projectId":37602,"projectName":null,"details":[{"amount":"8234743.0","currency":"USD","paymentDate":"2019-04-30T00:00:00"},{"amount":"8234743.0","currency":"USD","paymentDate":"2019-04-23T00:00:00"}]}]
const arr2=
[{"projectId":30278,"projectName":null,"details":[{"amount":"8097457.11","currency":"USD","paymentDate":"2016-05-16T00:00:00"}]},{"projectId":37602,"projectName":null,"details":[{"amount":"7234743.0","currency":"USD","paymentDate":"2019-04-30T00:00:00"},{"amount":"7234743.0","currency":"USD","paymentDate":"2019-04-23T00:00:00"}]}]
when i used ES6 spread operator, both values are appended to single array. But I want to merge based upon prjectId in that array.
So after merge, i need to get the result like below
const result =
[{"projectId":30278,"projectName":null,"details":[{"amount":"9097457.11","currency":"USD","paymentDate":"2016-05-16T00:00:00"},
{"amount":"8097457.11","currency":"USD","paymentDate":"2016-05-16T00:00:00"}
]},
{"projectId":37602,"projectName":null,"details":[{"amount":"8234743.0","currency":"USD","paymentDate":"2019-04-30T00:00:00"},{"amount":"8234743.0","currency":"USD","paymentDate":"2019-04-23T00:00:00"},
{"amount":"7234743.0","currency":"USD","paymentDate":"2019-04-30T00:00:00"},{"amount":"7234743.0","currency":"USD","paymentDate":"2019-04-23T00:00:00"}
]}]
const arr1=
[{"projectId":30278,"projectName":null,"details":[{"amount":"9097457.11","currency":"USD","paymentDate":"2016-05-16T00:00:00"}]},{"projectId":37602,"projectName":null,"details":[{"amount":"8234743.0","currency":"USD","paymentDate":"2019-04-30T00:00:00"},{"amount":"8234743.0","currency":"USD","paymentDate":"2019-04-23T00:00:00"}]}]
const arr2=
[{"projectId":30278,"projectName":null,"details":[{"amount":"8097457.11","currency":"USD","paymentDate":"2016-05-16T00:00:00"}]},{"projectId":37602,"projectName":null,"details":[{"amount":"7234743.0","currency":"USD","paymentDate":"2019-04-30T00:00:00"},{"amount":"7234743.0","currency":"USD","paymentDate":"2019-04-23T00:00:00"}]}]
var fullArray = [...arr1,...arr2];
var mergedData ={};
fullArray.forEach(function(data){
if(mergedData[data.projectId]){
mergedData[data.projectId]["details"] = mergedData[data.projectId]["details"].concat(data.details)
} else {
mergedData[data.projectId] = data;
}
})
console.log(Object.values(mergedData))
You can easily achieve that using Lodash unionBy function.
const result = _.unionBy(arr1, arr2, 'projectId')
You can also try this in this case scenario.
let mergedArr = [];
let projectIdsArr1 = arr1.map(item => item.projectId);
arr2.map(outerLoopItem => {
if (projectIdsArr1.includes(outerLoopItem.projectId)) {
let found = arr1.find(innerLoopItem => innerLoopItem.projectId === outerLoopItem.projectId);
found.details = [...found.details, ...outerLoopItem.details];
mergedArr.push(found);
} else mergedArr.push(outerLoopItem);
});
console.log(mergedArr);

Java script filter on array of objects and push result's one element to another array

I have a array called data inside that array I have objects.
An object structure is like this
{
id:1,
especial_id:34,
restaurant_item:{id:1,restaurant:{res_name:'KFC'}}
}
I want to pass a res_name eg:- KFC
I want an output as a array which consists all the especial_ids
like this
myarr = [12,23,23]
I could do something like this for that. But I want to know what is more elegant way to do this.
const data = [
{id:1,especial_id:6,restaurant_items:{id:5,res_name:'McDonalds'}},
{id:1,especial_id:8,restaurant_items:{id:5,res_name:'Kfc'}},
{id:1,especial_id:6,restaurant_items:{id:5,res_name:'Sunmeal'}},
{id:1,especial_id:6,restaurant_items:{id:5,res_name:'Kfc'}},
];
let temp = data.filter(element => element.restaurant_items.res_name == 'kfc')
let myArr = [];
temp.forEach(element=> myArr.push(element.especial_id));
console.log(myArr)//[8,6]
You can try this. It uses "Array.filter" and "Array.map"
var data = [
{id:1,especial_id:6,restaurant_items:{id:5,res_name:'McDonalds'}},
{id:1,especial_id:8,restaurant_items:{id:5,res_name:'Kfc'}},
{id:1,especial_id:6,restaurant_items:{id:5,res_name:'Sunmeal'}},
{id:1,especial_id:6,restaurant_items:{id:5,res_name:'Kfc'}},
];
function getEspecialIdsByName(name) {
return data.filter(d => d.restaurant_items.res_name.toLowerCase() == name.toLowerCase())
.map(d => d.especial_id)
}
console.log(getEspecialIdsByName('Kfc'))
console.log(getEspecialIdsByName('Sunmeal'))
You can reduce to push elements which pass the test to the accumulator array in a single iteration over the input:
const data = [
{id:1,especial_id:6,restaurant_items:{id:5,res_name:'McDonalds'}},
{id:1,especial_id:8,restaurant_items:{id:5,res_name:'Kfc'}},
{id:1,especial_id:6,restaurant_items:{id:5,res_name:'Sunmeal'}},
{id:1,especial_id:6,restaurant_items:{id:5,res_name:'Kfc'}},
];
console.log(
data.reduce((a, { especial_id, restaurant_items: { res_name }}) => {
if (res_name === 'Kfc') a.push(especial_id)
return a;
}, [])
);
Use Array.reduce
const data = [{id:1,especial_id:6,restaurant_items:{id:5,res_name:'McDonalds'}},{id:1,especial_id:8,restaurant_items:{id:5,res_name:'Kfc'}},{id:1,especial_id:6,restaurant_items:{id:5,res_name:'Sunmeal'}},{id:1,especial_id:6,restaurant_items:{id:5,res_name:'Kfc'}}];
let result = data.reduce((a,c) => {
if(c.restaurant_items.res_name === 'Kfc') a.push(c.especial_id);
return a;
},[]);
console.log(result);

JavaScript or Lodash find objects by key

In an array of objects with diff keys, how do I find objects by key using ES6 or Lodash?
const arr = [{a:2}, {b:3}, {fred:10}]
I want the result to be:
=> [{a:2}, {fred:10}]
I don't want to use an omit style approach.
const filtered = arr.filter(obj => obj.hasOwnProperty("a") || obj.hasOwnProperty("fred"));
// or, if you have dynamic / lots of keys:
const keys = ["a", "fred"];
const filtered = arr.filter(obj => keys.some(key => obj.hasOwnProperty(key));
filter method will be useful. Create a function and pass an array of keys. Inside filter function check if the key is matching with the parameter array. If it passed then return that object
var orgObject = [{
a: 2
}, {
b: 3
}, {
fred: 10
}];
function searchByKey(keyNames) {
return orgObject.filter(function(item) {
for (var keys in item) {
if (keyNames.indexOf(keys) !== -1) {
return item
}
}
})
}
console.log(searchByKey(['a', 'fred']))
Basically you want all the objects from the array who have the fields a or fred. You can use the hasOwnProperty() on the objects while filtering.
_.filter(array, elem => elem.hasOwnProperty('a') || elem.hasOwnProperty('fred'));

Collecting a list of all object keys that meet certain criteria

I have a function getActiveProp:
const getActiveProp = obj => Object.keys(obj).find(k => obj[k].active);
But now, instead of finding the first item matching the criteria, I want to get an array of all of them.
I know I could simply do something like this, and wrap it in a function:
var arr = ['foo', 'bar', 'baz'];
var arr2 = [];
arr.forEach(k => arr2.push(k));
But I was just wondering if there was a one-line way to do it, creating the array within the forEach method itself, or using some similar array method to do it. Can that be done?
Use Array#filter in place of Array#find:
let object = {
inactiveProp1: { active: false },
activeProp1: { active: true },
activeProp2: { active: true }
}
const getActiveProps = o => Object.keys(o).filter(k => o[k].active)
console.log(getActiveProps(object))

Categories

Resources