Ramda compare two arrays of objects based on one property - javascript

I have 2 arrays:
arr1 = [
{
id: "1",
name: "Test 1"
},
{
id: "2",
name: "Test 2"
}
]
arr2 = [
{
groupId: "125",
age: 44,
subGroup: {
id: "1",
name: "Test 1"
}
}
]
Using Ramda, I need to compare arr1 and arr2, and return matching object from arr2 based on id (id: "1")
So the result should be:
[
{
groupId: "125",
age: 44,
subGroup: {
id: "1",
name: "Test 1"
}
}
]

Use R.innerJoin() to intersect between two arrays (arr2 & arr1), and get items from the 1st array (arr2 in your case):
const fn = R.innerJoin((a, b) => a.subGroup?.id === b.id)
const arr1 = [{"id":"1","name":"Test 1"},{"id":"2","name":"Test 2"}]
const arr2 = [{"groupId":"125","age":44,"subGroup":{"id":"1","name":"Test 1"}},{"groupId":"126","age":46}]
const result = fn(arr2, arr1)
console.log(result)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>

Related

How to check array of objects based on ID and add new property in JavaScript

I have two array of objects arr1 and arr2
if arr1 and arr2 id matches, then push arr1 property name to arr2 in javascript
var arr1 = [
{id: 1, name : "Helena"},
{id: 2, name : "John"}
]
var arr2 = [{
country: "MY",
details: [{
mode: "parttime",
members:[{id:1}, {id: 2}]
}]
}]
Expected Output:
[{
country: "MY",
details:[{
mode: "parttime",
members: [
{id:1, name: "Helena"},
{id: 2, name: "john"}
]
}]
}]
Please try:
var arr1 = [
{
id: 1,
name: "Helena",
},
{
id: 2,
name: "John",
},
];
var arr2 = [
{
country: "MY",
details: [
{
mode: "parttime",
members: [
{
id: 1,
},
{
id: 2,
},
],
},
],
},
];
function getCountriesWithMemberNames(membersArr, countriesArr) {
// mapping each country obj in the array to a modified country
return countriesArr.map((country) => {
return {
...country, // take all existing country info
// modify country.details, mapping it to a new object
details: country.details.map((detail) => {
return {
...detail, // take all details
// modying members
members: detail.members.map((member) => {
const memberObj = { ...member };
// check if name exists for this member
const name = membersArr.find((i) => i.id === member.id).name;
if (name) {
memberObj.name = name;
}
return memberObj;
}),
};
}),
};
});
}
console.log(getCountriesWithMemberNames(arr1, arr2));

Best way to find the difference between 2 arrays of objects

I have these 2 arrays of objects.
Sorry that I post the image because I want you guys to quickly understand my points.
What is the best way to compare 2 arrays of objects and look for what is not in it?
I can do 2 levels for loops and an if-check, but I'm not sure if it is the best approach.
I am seeking a better performance JS way to achieve something like this.
This is what I am looking to extract while comparing arr1 & arr2.
{
"id": 4,
"name": "Date and Time"
}
One way is to concatenate both arrays together, then iterate and filter to see if that id exists in both arrays. If it doesn't exist in both arrays, it's extra.
a1.concat(a2).filter(a => a1.findIndex(f => f.id === a.id) == -1 || a2.findIndex(f => f.id === a.id) == -1)
let arr1 = [{"id": 1,"name": "Date and Time"},{"id": 2,"name": "Date and Time"},{"id": 3,"name": "Date and Time"},{"id": 4,"name": "Date and Time"}]
let arr2 = [{"id": 1,"name": "Date and Time"},{"id": 2,"name": "Date and Time"},{"id": 3,"name": "Date and Time"}]
const findMissing = (a1, a2) => a1.concat(a2).filter(a => a1.findIndex(f => f.id === a.id) == -1 || a2.findIndex(f => f.id === a.id) == -1)
console.log(findMissing(arr1, arr2))
Different ways to achieve this requirement. I also created a performance check based on all the below 3 solutions here. Kindly run this test suite and based on the result you can use any of the below solution in your project.
Filtered out the array by using Array.filter() method and find the id in the another array by using Array.find() method.
const arr1 = [{
id: 1,
name: "Weather"
}, {
id: 2,
name: "Geo Location"
}, {
id: 3,
name: "Device"
}];
const arr2 = [{
id: 1,
name: "Weather"
}, {
id: 2,
name: "Geo Location"
}, {
id: 3,
name: "Device"
}, {
id: 4,
name: "Date and Time"
}];
const res = arr2.filter((obj) => !arr1.find(({ id }) => obj.id === id));
console.log(res);
By using Array.includes() method.
const arr1 = [{
id: 1,
name: "Weather"
}, {
id: 2,
name: "Geo Location"
}, {
id: 3,
name: "Device"
}];
const arr2 = [{
id: 1,
name: "Weather"
}, {
id: 2,
name: "Geo Location"
}, {
id: 3,
name: "Device"
}, {
id: 4,
name: "Date and Time"
}];
const IDArray = arr1.map(obj => obj.id);
const res = arr2.filter(obj => !IDArray.includes(obj.id));
console.log(res);
Use Array.some() along with Array.filter() method.
const arr1 = [{
id: 1,
name: "Weather"
}, {
id: 2,
name: "Geo Location"
}, {
id: 3,
name: "Device"
}];
const arr2 = [{
id: 1,
name: "Weather"
}, {
id: 2,
name: "Geo Location"
}, {
id: 3,
name: "Device"
}, {
id: 4,
name: "Date and Time"
}];
const res = arr2.filter(({ id }) => !arr1.some(x => x.id == id))
console.log(res)

How to get array of objects only if array values matches with object array key

I have array arr1, arr2, arr3 and object array objarr
I would like to get array of objects based on condition
i.e
when passing arr1,
object array objarr should return only matched keys of arr1
i.e
when passing arr2,
object array objarr should return only matched keys of arr2 (if wrk is passed parameter only show that is true )
i.e
when passing arr3,
object array objarr should return only matched keys of arr3
var arr1=["name", "place"]
var arr2=["details", "wrk"]
var arr3=["name"]
var objarr=[
{id:1, name: "ayan", place: "MY", details: "finance" , wrk: true},
{id:2, name: "mike", place: "AU", details: "teaching", wrk: false },
{id:3, name: "john", place: "DE", details: "service" , wrk: true}
]
function outputData(arr1){
var final=[];
var result = objarr.map(e=>{
if(arr1.includes(Object.keys(e)){
final.push(e)
}
})
return final
;}
Expected Output;
//for arr1 is passed
[
{name: "ayan", place: "MY"},
{name: "mike", place: "AU"},
{name: "john", place: "DE"}
]
//for arr2 is passed
[
{details: "finance", wrk:true},
{details: "service", wrk: true}
]
//for arr3 is passed
[
{name: "ayan"},
{name: "mike"},
{name: "john"}
]
var arr1 = ["name", "place"];
var arr2 = ["details", "wrk"];
var arr3 = ["name"];
var objarr = [
{ id: 1, name: "ayan", place: "MY", details: "finance", wrk: true },
{ id: 2, name: "mike", place: "AU", details: "teaching", wrk: false },
{ id: 3, name: "john", place: "DE", details: "service", wrk: true }
]
function outputData(arr) {
var final = [];
objarr.forEach(obj => {
const temp = {};
arr.forEach(key => {
if(obj[key]){
temp[key]= obj[key];
}
});
if(Object.keys(temp).length===arr.length){
final.push(temp);}
});
return final;
}
console.log('arr1',outputData(arr1));
console.log('arr2',outputData(arr2));
console.log('arr3',outputData(arr3));
You can easily achieve the result using reduce and for..of loop
var arr1 = ["name", "place"];
var arr2 = ["details", "wrk"];
var arr3 = ["name"];
var objarr = [
{ id: 1, name: "ayan", place: "MY", details: "finance", wrk: true },
{ id: 2, name: "mike", place: "AU", details: "teaching", wrk: false },
{ id: 3, name: "john", place: "DE", details: "service", wrk: true },
];
function getData(target, source) {
return target.reduce((acc, curr) => {
const obj = {};
for (let prop of source) {
obj[prop] = curr[prop];
}
if (Object.keys(obj).includes("wrk")) {
if (obj["wrk"]) acc.push(obj);
} else acc.push(obj);
return acc;
}, []);
}
console.log(getData(objarr, arr1));
console.log(getData(objarr, arr2));
console.log(getData(objarr, arr3));
/* This is not a part of answer. It is just to give the output fill height. So IGNORE IT */
.as-console-wrapper { max-height: 100% !important; top: 0; }
Try this solution:
function outputData(arr) {
return objarr.map(obj => Object.fromEntries(arr.map(k => [k, obj[k]])))
}
Since you need to select only specific nodes from objarr, going for Array.map willnot give the result. Use Some other looping logic for that.
I used Array.reduce here.
Logic
Loop through objarr with Array.reduce.
Loop through the paremeter array inside the reduce.
Check if the value for each node from the parameter array in the object in objarr array.
If the value is truthy, add that to an object.
If the length of keys of this object is same as the length of parameter array, push this object to accumulator.
Please Note: This logic checks truthy value for key "wrk" only. If you want to check for all boolean values, you can use the condition added as comment just above the if statement
var arr1 = ["name", "place"]
var arr2 = ["details", "wrk"]
var arr3 = ["name"]
var objarr = [
{ id: 1, name: "ayan", place: "MY", details: "finance", wrk: true },
{ id: 2, name: "mike", place: "AU", details: "teaching", wrk: false },
{ id: 3, name: "john", place: "DE", details: "service", wrk: true }
]
function outputData(arr) {
var result = objarr.reduce((acc, currNode) => {
const resp = {};
arr.forEach((option) => {
// Current condition is only for "wrk"
// To check truthy state for all boolean variables use the below condition
// ((typeof currNode[option] === "boolean" && currNode[option]) || typeof currNode[option] !== "boolean")
if ((option === "wrk" && currNode[option]) || option !== "wrk") {
resp[option] = currNode[option]
}
})
if(Object.keys(resp).length === arr.length) {
acc.push(resp)
}
return acc
}, []);
return result;
}
console.log(outputData(arr1));
console.log(outputData(arr2));
console.log(outputData(arr3));

In array of objects count grouped values by certain key

I have a following data:
const data2 = [
{
App: "testa.com",
Name: "TEST A",
Category: "HR",
Employees: 7
},
{
App: "testd.com",
Name: "TEST D",
Category: "DevOps",
Employees: 7
},
{
App: "teste.com",
Name: "TEST E",
Category: "DevOps",
Employees: 7
},
{
App: "testf.com",
Name: "TEST F",
Category: "Business",
Employees: 7
}
]
I want to get the count of distinct categories: Right now I am getting the list of all distinct categories but I'm unable to compute their count.
Following snippet give me the Distinct Category:
let uniqueCategory = [];
for(let i = 0; i < result.data.length; i++){
if(uniqueCategory.indexOf(result.data[i].Category) === -1){
uniqueCategory.push(result.data[i].Category);
}
}
What changes should I make to get the Counts of those Categories in the uniqueCategory - something like following:
uniqueCategory = [
{Category: "DevOps", count: 5},
{Category: "Business", count: 4},
....
{}
]
Your approach implies looping your source array (with .indexOf()) every iteration of for(..-loop. That will slow down unnecessarily look up process.
Instead, you may employ Array.prototype.reduce() to traverse your source array and build up the Map, having Category as a key and object of desired format as a value, then extract Map.prototype.values() into resulting array.
That will perform much faster and scale better.
const src = [{App:"testa.com",Name:"TEST A",Category:"HR",Employees:7},{App:"testd.com",Name:"TEST D",Category:"DevOps",Employees:7},{App:"teste.com",Name:"TEST E",Category:"DevOps",Employees:7},{App:"testf.com",Name:"TEST F",Category:"Business",Employees:7}],
result = [...src
.reduce((r, {Category}) => {
const cat = r.get(Category)
cat ? cat.count ++ : r.set(Category, {Category, count: 1})
return r
}, new Map)
.values()
]
console.log(result)
.as-console-wrapper{min-height:100%;}
The easiest way to do it is to use Array.prototype.reduce
const arr = [ ... ];
const output = arr.reduce((result, obj) => {
if (!result[obj.category]) {
result[obj.category] = 0;
}
result[obj.category]++;
return result;
}, {});
console.log(output); // this should log the similar output you want
Here's another alternative using .map and Set:
const src = [
{
App: "testa.com",
Name: "TEST A",
Category: "HR",
Employees: 7
},
{
App: "testd.com",
Name: "TEST D",
Category: "DevOps",
Employees: 7
},
{
App: "teste.com",
Name: "TEST E",
Category: "DevOps",
Employees: 7
},
{
App: "testf.com",
Name: "TEST F",
Category: "Business",
Employees: 7
}
];
const categories = src.map(obj => obj.Category);
const distinctCategories = [...new Set(categories)];
console.log(distinctCategories.length);

How sort array with objects by two diffrent keys?

I have no idea how I can sort an array of objects comparing two keys. I have array:
const arr = [
{
age: "20",
group: "XXX",
id: "3L1aa1558002753379",
menu: "standard",
name: "Adam"
},
{
age: "22",
group: "XXX",
id: "xhNt11558002753379",
menu: "standard",
name: "Ola"
},
{
otherid: "3L1aa1558002753379",
age: "25",
group: "YYY",
id: "6ryVK1558002753379",
menu: "standard",
name: "Wommman"
},
{
otherid: "xhNt11558002753379",
age: "25",
group: "YYY",
id: "aL1aa1558002753312",
menu: "standard",
name: "xxxxxy"
},
{
age: "25",
group: "YYY",
id: "6ryVK1558002753379",
menu: "standard",
name: "xxxxxo"
}
,
{
otherid: "1ryVK1558002753372",
age: "25",
group: "YYY",
id: "9ryVK155a002753370",
menu: "standard",
name: "xxxxxo"
},
{
age: "25",
group: "YYY",
id: "1ryVK1558002753372",
menu: "standard",
name: "xxxxxo"
}
];
I want to sort in this way: if "id" and "otherid" is the same - let objects be next to each other. I do not know how to do it, would anyone be so good?
Like here:
const arr = [
{
age: "20",
group: "XXX",
id: "3L1aa1558002753379",
menu: "standard",
name: "Adam"
},
{
otherid: "3L1aa1558002753379",
age: "25",
group: "YYY",
id: "6ryVK1558002753379",
menu: "standard",
name: "Wommman"
},
{
age: "22",
group: "XXX",
id: "xhNt11558002753379",
menu: "standard",
name: "Ola"
},
{
otherid: "xhNt11558002753379",
age: "25",
group: "YYY",
id: "aL1aa1558002753312",
menu: "standard",
name: "xxxxxy"
},
{
age: "25",
group: "YYY",
id: "1ryVK1558002753372",
menu: "standard",
name: "xxxxxo"
},
{
otherid: "1ryVK1558002753372",
age: "25",
group: "YYY",
id: "9ryVK155a002753370",
menu: "standard",
name: "xxxxxo"
},
{
age: "25",
group: "YYY",
id: "6ryVK1558002753379",
menu: "standard",
name: "xxxxxo"
}
,
];
I tried something similar to this: Javascript sort array by two fields but it failed
You pointed out, that you only need to compute pairs and render them in a react application.
It would make much more sense to structure your data in a way your view can directly render it.
Since you are in control of the data, you don't need to generate a flat list. You can setup the pairs (of students, or whatever) using a hierarchical structure, or nested obejcts.
let students = [{name: 'Jon', id:0}, {name: 'Peter', id: 1}, {name: 'Steve', id:2}, {name: 'Joe', id: 3}]
let pairs = [{a: students [3], b: students[1]}, {a: students [2], b: students [0]}];
console.log (pairs);
Now if you want to render those pairs, you already have the data in the structure you need.
render () {
return pairs.map (pair => <Pair data={pair} />)
}
You can also flatten the pairs array and render a flat list of elements next to each other if you prefer.
let students = [{name: 'Jon', id:0}, {name: 'Peter', id: 1}, {name: 'Steve', id:2}, {name: 'Joe', id: 3}]
let pairs = [{a: students [3], b: students[1]}, {a: students [0], b: students [2]}];
const flatten = (flat, {a, b}) => [...flat, a, b];
const sorted = pairs.reduce (flatten, []);
console.log (sorted)
const Student = data => <div>{data.name}</div>
const Pair = pair => <div>
<Student data={pair.a} />
<Student data={pair.b} />
</div>
const renderFlat = () => {
return sorted.map (student => <Student data={student} />
}
const renderPairs = () => {
reutnr pairs.map (pair => <Pair data={pair} />)
}
I hope I make at least a bit sense. - Here is the sort function in any case
function sort (arr) {
let otherids = arr.reduce ((lkp, obj) => {
if (obj.otherid)
lkp [obj.otherid] = obj;
return lkp;
}, {});
let sorted = [];
for (var i=0; i < arr.length; i++) {
let obj = arr [i];
if (!!~sorted.indexOf (obj)) continue;
if (otherids [obj.id]) {
sorted.push (obj)
sorted.push(otherids[obj.id])
}
}
return sorted.concat (arr.filter (obj => !~sorted.indexOf (obj)));
}
let sorted = sort (arr);
console.log (sorted);
<script>var arr=[{age:"20",group:"XXX",id:"3L1aa1558002753379",menu:"standard",name:"Adam"},{age:"22",group:"XXX",id:"xhNt11558002753379",menu:"standard",name:"Ola"},{otherid:"3L1aa1558002753379",age:"25",group:"YYY",id:"6ryVK1558002753379",menu:"standard",name:"Wommman"},{otherid:"xhNt11558002753379",age:"25",group:"YYY",id:"aL1aa1558002753312",menu:"standard",name:"xxxxxy"},{age:"25",group:"YYY",id:"6ryVK1558002753379",menu:"standard",name:"xxxxxo"},{otherid:"1ryVK1558002753372",age:"25",group:"YYY",id:"9ryVK155a002753370",
menu:"standard",name:"xxxxxo"},{age:"25",group:"YYY",id:"1ryVK1558002753372",menu:"standard",name:"xxxxxo"}];</script>
The key to sorting strings is to use String.localeCompare(). Numbers, dates and booleans are much simpler.
Here is an example of sorting a list of Objects by two string columns - name and menu:
arr.sort(function comparerFn(L, R){
if(L.name !== R.name)
return (new String(L.name)).localeCompare(R.name)===1?1:-1
if(L.menu !== R.menu)
return (new String(L.menu)).localeCompare(R.menu)===1?1:-1
return 0
})
Reasoning for odd ===1?1:-1 syntax: localeCompare() returns 1 or 0 but sort compareFn requires either 0: (leave sorting as-is), >0: (L is before R), <0: (R is before L)

Categories

Resources