JavaScript or Lodash find objects by key - javascript

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'));

Related

Merge Javascript Objects WITH Same Key AND Include Duplicate Values WHERE Key Matches

I am trying to merge some JSON data sets BY key value WHILE including duplicate values WHERE the key matches.
I have tried this quite a bit now but can't seem to produce the object that I need.
Object 1
[
{"userId":"1",
"email":"email1#gmail.com"
},
{"userId":"2",
"email":"email2#gmail.com"
}
]
Object 2
[
{"id":"1abc",
"listingId":"4def",
"userId":"2"
},
{"id":"2abc",
"listingId":"2def",
"userId":"1"
},
{"id":"3abc",
"listingId":"3def",
"userId":"2"
}
]
I need to merge these objects in a way that looks like this:
Desired Output
[
{"id":"1abc",
"listingId":"4def",
"userId":"2",
"email":"email2#gmail.com"
},
{"id":"2abc",
"listingId":"2def",
"userId":"1",
"email":"email1#gmail.com"
},
{"id":"3abc",
"listingId":"3def",
"userId":"2",
"email":"email2#gmail.com"
}
]
Problems I am Experiencing
I am able to merge the data sets successfully using a function that looks like this:
function merge(a, b, key) {
function x(a) {
a.forEach(function (b) {
if (!(b[key] in obj)) {
obj[b[key]] = obj[b[key]] || {};
array.push(obj[b[key]]);
}
Object.keys(b).forEach(function (k) {
obj[b[key]][k] = b[k];
});
});
}
var array = [],
obj = {};
x(a);
x(b);
return array;
}
https://stackoverflow.com/a/35094948/1951144
But it produces results that look like this:
[
{"id":"1abc",
"listingId":"4def",
"userId":"2",
"email":"email2#gmail.com"
},
{"id":"2abc",
"listingId":"2def",
"userId":"1",
"email":"email1#gmail.com"
}
]
Is there a way to use the above function WHILE keeping AND including the duplicate values where my keys match?
For each element in arr2, create a new element containing the props of the item from arr2, and the email of the corresponding entry in arr1.
let arr1 = [
{"userId":"1",
"email":"email1#gmail.com"
},
{"userId":"2",
"email":"email2#gmail.com"
}
];
let arr2 = [
{"id":"1abc",
"listingId":"4def",
"userId":"2"
},
{"id":"2abc",
"listingId":"2def",
"userId":"1"
},
{"id":"3abc",
"listingId":"3def",
"userId":"2"
}
];
let output = arr2.map(a2 => ({...a2, email: arr1.find(a1 => a1.userId === a2.userId)?.email}));
console.log(output);
This solution works even if the key isn't known yet. .flatMap() both arrays and pass in the desired key (in example it's "userId"). Use Object.entries() on each object so they will be an array of pairs.
[{A1: A1v}, {A2: A2v},...]
// into
[[A1, A1v], [A2, A2v],...]
.flatMap() the second array and on each iteration .flatMap() the first array. Then compare the given key ("userID") with the key of each object from the second array ("a") AND the value of that key and the value of the key of the object in the first array.
a === key && av === bv
If both criteria are meet then merge those objects and return it, otherwise...
? {...objA, ...objB}
return an empty array, which ultimately results to nothing since .flatMap() flattens one level of arrays.
: []
const arrA=[{userId:"1",email:"email1#gmail.com"},{userId:"2",email:"email2#gmail.com"}];const arrB=[{id:"1abc",listingId:"4def",userId:"2"},{id:"2abc",listingId:"2def",userId:"1"},{id:"3abc",listingId:"3def",userId:"2"}];
function masterKey(primary, key, secondary) {
let result = secondary.flatMap(objB => Object.entries(objB).flatMap(([b, bv]) =>
primary.flatMap(objA => Object.entries(objA).flatMap(([a, av]) =>
a === key && av === bv ? {...objA, ...objB} : []))));
return result;
}
console.log(masterKey(arrA, "userId", arrB));

How to convert json object keys into different arrays removing the duplicate

I'm having the JSON like this i need to group this JSON with all the keys in JSON object and value should in array (excluding duplicates).
var people = [
{sex:"Male", name:"Jeff"},
{sex:"Female", name:"Megan"},
{sex:"Male", name:"Taylor"},
{sex:"Female", name:"Madison"}
];
My output should be like
{"sex":["Male","Female"],"name":["Jeff","Megan","Taylor","Madison"]}
how we can able to achieve this
function getValues(array) {
var result = {};
array.forEach(obj => {
Object.keys(obj).forEach(key => {
if(!Array.isArray(result[key]))
result[key] = [];
result[key].push(obj[key]);
})
})
return result;
}
You could use the Array.reduce() method to transform your array into a single object:
var people = [
{sex:"Male", name:"Jeff"},
{sex:"Female", name:"Megan"},
{sex:"Male", name:"Taylor"},
{sex:"Female", name:"Madison"}
];
const transformed = people.reduce((acc, e) => {
Object.keys(e).forEach((k) => {
if (!acc[k]) acc[k] = [];
if (!acc[k].includes(e[k])) acc[k].push(e[k]);
});
return acc;
}, {});
console.log(transformed);
If for one of the object keys (sex or name in this case) a value array does not exist, it is created. Before a value is pushed into any of the value arrays, it is verified that it is not already present in that array.

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.

Find an index of array item from another json array item

I am looking to find out an index and group the item belong to in a parent json group, how can I do it?
I am open to reformat the json as well if need be,
I tried JSON.stringify() but it returns the wrong index as well.
let Content = {
group1: [
[{content:"hello"},{content:"world"}],
[{content:"hello1"},{content:"world"}],
[{content:"hello2"},{content:"world"}],
[{content:"hello3"},{content:"world"}],
[{content:"hello4"},{content:"world"}],
[{content:"hello5"},{content:"world"}],
],
group2: [
[{content:"hello10"},{content:"world"}],
[{content:"hello11"},{content:"world"}],
[{content:"hello12"},{content:"world"}],
[{content:"hello13"},{content:"world"}],
[{content:"hello14"},{content:"world"}],
[{content:"hello15"},{content:"world"}],
],
};
// let currentItem = {type:'group2',index:5};
// let currentItemContent = Content[currentItem.type][currentItem.index];
let obj = [{content:"hello15"},{content:"world"}];
let newIndex = Content["group1"].indexOf(obj);
let type = "group1";
if(newIndex < 0)
{
type="group2"
console.log(Content["group2"]);
newIndex = Content["group2"].indexOf(obj);
}
console.log({"type":type,"index":newIndex});
expected: {type:'group2',index:5}
Loop through the Content object using for...in. Check if the given array is in each group by using findIndex. Since both the objects in the array seem to be in order, you can simply compare the string returned by JSON.stringify
let Content={group1:[[{content:"hello"},{content:"world"}],[{content:"hello1"},{content:"world"}],[{content:"hello2"},{content:"world"}],[{content:"hello3"},{content:"world"}],[{content:"hello4"},{content:"world"}],[{content:"hello5"},{content:"world"}]],group2:[[{content:"hello10"},{content:"world"}],[{content:"hello11"},{content:"world"}],[{content:"hello12"},{content:"world"}],[{content:"hello13"},{content:"world"}],[{content:"hello14"},{content:"world"}],[{content:"hello15"},{content:"world"}]]}
function find(input, search) {
for (const type in input) {
const group = input[type];
const index = group.findIndex(a => JSON.stringify(a) === JSON.stringify(search));
if (index != -1)
return { type, index }
}
return null
}
console.log(find(Content, [{content:"hello15"},{content:"world"}]))
console.log(find(Content, [{content:"hello"},{content:"world"}]))
You could also use Array.find in combination with Object.keys and Array.some. The array comparison you can do via JSON.stringify however remember that if your keys are in different order that would not work:
[{content:"world"},{content:"hello"}] vs [{content:"hello"},{content:"world"}]
would not match as you would expect since you are matching on strings and they are now different.
let Content = { group1: [ [{content:"hello"},{content:"world"}], [{content:"hello1"},{content:"world"}], [{content:"hello2"},{content:"world"}], [{content:"hello3"},{content:"world"}], [{content:"hello4"},{content:"world"}], [{content:"hello5"},{content:"world"}], ], group2: [ [{content:"hello10"},{content:"world"}], [{content:"hello11"},{content:"world"}], [{content:"hello12"},{content:"world"}], [{content:"hello13"},{content:"world"}], [{content:"hello14"},{content:"world"}], [{content:"hello15"},{content:"world"}], ], };
let findArray = (data, obj) => {
let index, group = Object.keys(data).find((k,i) => {
index = i
return data[k].some(x => JSON.stringify(x) === JSON.stringify(obj))
})
return { index, group }
}
console.log(findArray(Content, [{content:"hello"},{content:"world"}]))
console.log(findArray(Content, [{content:"hello10"},{content:"world"}]))

Get objects in array with duplicated values

I need to get elements from an array of objects where one of that object's properties (name in this case) is duplicated--in other words, appears in some other object in the array.
data
var data = [
{id:1, name:"sam", userid:"ACD"},
{id:1, name:"ram", userid:"SDC"},
{id:1, name:"sam", userid:"CSTR"}
];
i need to check all row and get all the array value where name property is duplicating.
the expected output:
[
{id:1, name:"sam", userid:"ACD"},
{id:1, name:"sam", userid:"CSTR"}
]
my code
Array.from(data).map(x => x.name)
but it is returning all the values.
The code should not create any performance issue because array will contain more than 500 rows.
Angular is a framework, not a language. There is no Angular in your problem.
Let me understand if I understood well. You have an array of objects and you want to keep all the elements that are duplicate and get rid of others, all right? You can try:
data.reduce((acc, value, i, arr) => {
if(acc.some(v => v.name === value.name)) return acc;
let filtered = arr.filter(v => v.name === value.name);
return filtered.length > 1 ? acc.concat(filtered) : acc;
}, []);
Or you can sort your array in first instance, in order to improve performance:
const sort = (a, b) => a.name.toUpperCase() < b.name.toUpperCase() ? -1 : 1;
let duplicates = [];
let sortedArray = data.sort(sort);
for(let i=0; i<sortedArray.length - 1; i++) {
if(sortedArray[i].name === sortedArray[i+1].name) {
duplicates.push(sortedArray[i], sortedArray[i+1]);
i++;
}
}
The brute force approach would be to filter the array to keep only those elements with duplicated names, as expressed by the filter function duplicateName.
// Is there more than one element in an array satisfying some predicate?
const hasMultiple = (arr, pred) => arr.filter(pred).length > 1;
// Is this element a duplicate in the context of the array?
const duplicateName = (elt, idx, arr) => hasMultiple(arr, e => e.name === elt.name);
// Test data.
var data = [
{id:1,name:"sam", userid:"ACD"},
{id:1,name:"ram", userid:"SDC"},
{id:1,name:"sam", userid:"CSTR"}
];
console.log(data.filter(duplicateName));
However, this is going to have poor performance (O(n^2)) in the case of many elements. To solve that problem, you're going to need to preprocess the array. We'll create an object with a property for each name, whose value is an array of all the elements in which that name occurs. This operation is usually called groupBy. Several popular libraries such as underscore will provide this for you. We'll write our own. After grouping, we will filter the object of groups to remove those with only one member.
// Group an array by some predicate.
const groupBy = (arr, pred) => arr.reduce((ret, elt) => {
const val = pred(elt);
(ret[val] = ret[val] || []).push(elt);
return ret;
}, {});
// Filter an object, based on a boolean callback.
const filter = (obj, callback) => Object.keys(obj).reduce((res, key) => {
if (callback(obj[key], key, obj)) res[key] = obj[key];
return res;
}, {});
// Remove groups with only one element.
const removeNonDups = groups => filter(groups, group => group.length > 1);
// Test data.
var data = [
{id:1,name:"sam", userid:"ACD"},
{id:1,name:"ram", userid:"SDC"},
{id:1,name:"sam", userid:"CSTR"}
];
console.log(removeNonDups(groupBy(data, elt => elt.name)));

Categories

Resources