Checking an object that contains arrays of objects for a value - javascript

I see this question has been touched on a lot on stack overflow but I can't seem to find one that helps my issue. I have an object that contains many arrays with objects nested inside. I need to find the key of the array that contains the object that a usersID. Ive tried .filter and for in loops but I keep getting errors.
My data looks like this :
{
FL: [{id: "mp-2d24973e-c610-4b1c-9152...}{id...}],
TX: [{id: "mp-2d24973e-c610-4b1c-9152...}{id...}],
LA: [{id: "mp-2d24973e-c610-4b1c-9152...}{id...}],
}
Is there a method that allows me to check for a value inside the arrays and if it is found returns the key to that array ie. FL or TX?
const practices = data.items
for (const [key, value] of Object.entries(practices)){
console.log(key, value, "KEYVALUE")
if(value.id === currentUser.currentPracticeID){
console.log(key)
}
}
Of course this code doesnt work but this what Ive tried so far. Im still new to dev so any point in the right direction would be great.

A simple filter() inside of a for...in loop would do it. After looking at the other answers, I should say this will return the first matching ID, rather than an array of all matching ID's like #Barmars answer
const practices = {
FL: [{id: "mp-2d24973e-c610-4b1c-9152"},{id:"3"}],
TX: [{id: "mp-2d24973e-c610-4b1c-9153"},{id:"4"}],
LA: [{id: "mp-2d24973e-c610-4b1c-9154"},{id:"5"}],
}
const findUserKey = (u) => {
for (const key in practices) {
if (practices[key].filter(mp => mp.id === u.currentPracticeID).length>0) return key
}
return false;
}
let currentUser = {currentPracticeID: "mp-2d24973e-c610-4b1c-9154"}
let check_mp = findUserKey(currentUser)
console.log(check_mp)

You can use Object#keys to get the list of object keys, Array#find to iterate over this list, and Array#findIndex to check if the array at each iteration has the userId you're searching for:
const getKeyOfUserId = (obj = {}, userId) =>
Object.keys(obj).find(key =>
obj[key].findIndex(({ id }) => id === userId) >= 0
);
const obj = {
FL: [{id: "mp-2d24973e-c610-4b1c-9152"},{id:"mp-2d24973e-c610-4b1c-9153"}],
TX: [{id: "mp-2d24973e-c610-4b1c-9154"},{id:"mp-2d24973e-c610-4b1c-9155"}],
LA: [{id: "mp-2d24973e-c610-4b1c-9156"},{id:"mp-2d24973e-c610-4b1c-9157"}]
};
console.log( getKeyOfUserId(obj, "mp-2d24973e-c610-4b1c-9156") );

filter() is an array method, practices is an object. You need to use Object.entries() to get an array of keys and values.
Then you can use .some() to test if any of the objects in the nested array contain the ID you're looking for.
const practices = {
FL: [{
id: "mp-2d24973e-c610-4b1c-9152"
}, {
id: "mp-2d24973e-c610-4b1c-9153"
}],
TX: [{
id: "mp-2d24973e-c610-4b1c-9154"
}, {
id: "mp-2d24973e-c610-4b1c-9155"
}],
LA: [{
id: "mp-2d24973e-c610-4b1c-9156"
}, {
id: "mp-2d24973e-c610-4b1c-9157"
}]
};
let currentPracticeID = "mp-2d24973e-c610-4b1c-9156";
const states = Object.entries(practices).filter(([key, arr]) => arr.some(({
id
}) => id == currentPracticeID)).map(([key, arr]) => key);
console.log(states);

Here is how I would do it:
const data = {
FL: [{id: 'ab'}, {id: 'cd'}, {id: 'ef'}],
TX: [{id: 'hi'}, {id: 'jk'}, {id: 'lm'}],
LA: [{id: 'no'}, {id: 'pq'}, {id: 'rs'}]
};
const findKey = (id) => {
let foundKey;
Object.entries(data).some(([key, objects]) => {
if (objects.find(object => object.id === id)) {
foundKey = key;
return true;
}
});
return foundKey;
};
console.log(`The data: ${JSON.stringify(data)}`);
console.log(`Looking for object with ID "jk": ${findKey('jk')}`);
You loop through the entries of your data, so you have the key and the objects for that key. You simply use objects.find to see which object matches the ID you're looking for. I would use array.some for this as it stops the loop when you return true, and foundKey will simply be falsy if nothing is found.

Related

Get values from objects in array with rest parameter

let newValues = user.info.socialMedia ? [...user.info.socialMedia] : []
So here we get several objects into the array that have an id key, and instead of the objects themselves I want to have only the id strings in this array. How can I get this working? I am quite new to Javascript, so it would be nice to get some help here.
I tried a for of then a for in loop to get the ids out of there and push them to the array, tho this does not work for my case.
instead of the objects themselves I want to have only the id strings
That sounds like a .map() operation, to project one array into another by applying a transformation to each object. Something like this:
let newValues = user.info.socialMedia ? user.info.socialMedia.map(s => s.id) : []
Or perhaps simpler:
let newValues = user.info.socialMedia?.map(s => s.id) ?? []
For example:
let user = {
info: {
socialMedia: [
{ id: 1, name: 'Ron' },
{ id: 2, name: 'Tammy' },
{ id: 3, name: 'Tammy 2' }
]
}
};
let newValues = user.info.socialMedia?.map(s => s.id) ?? []
console.log(newValues);

Push only certain items from array of objects to new array of arrays

Hello so i have array of objects something like this
const old = [{id: 1, name: 'Random'}, {id: 2, name: 'Random2'}]
also i have array
const wantedField = ['id']
So looking this result, i need values only for certain key
const finally = [[1],[2]]
I have tried something like this but not luck. End result should be array of arrays with just certain values.
old.map((obj, value) => {
const key = Object.keys(obj)[value]
if(wantedField.includes(const)) {
const newArray = []
const key = Object.keys(obj)[value]
newArray.push(obj[key])
return [newArray]
}
})
So this return [newArray] is wrong should return multiple values not just one. Please help regards.
This is a one-liner, with two nested maps. One to iterate over the input array, and another to iterate over the wanted field(s):
const old = [{id: 1, name: 'Random'}, {id: 2, name: 'Random2'}];
const wantedField = ['id'];
const result = old.map(o => wantedField.map(k => o[k]));
console.log(result);

Creating a JavaScript function that filters out duplicate in-memory objects?

Okay, so I am trying to create a function that allows you to input an array of Objects and it will return an array that removed any duplicate objects that reference the same object in memory. There can be objects with the same properties, but they must be different in-memory objects. I know that objects are stored by reference in JS and this is what I have so far:
const unique = array => {
let set = new Set();
return array.map((v, index) => {
if(set.has(v.id)) {
return false
} else {
set.add(v.id);
return index;
}
}).filter(e=>e).map(e=>array[e]);
}
Any advice is appreciated, I am trying to make this with a very efficient Big-O. Cheers!
EDIT: So many awesome responses. Right now when I run the script with arbitrary object properties (similar to the answers) and I get an empty array. I am still trying to wrap my head around filtering everything out but on for objects that are referenced in memory. I am not positive how JS handles objects with the same exact key/values. Thanks again!
Simple Set will do the trick
let a = {'a':1}
let b = {'a': 1,'b': 2, }
let c = {'a':1}
let arr = [a,b,c,a,a,b,b,c];
function filterSameMemoryObject(input){
return new Set([...input])
}
console.log(...filterSameMemoryObject(arr))
I don't think you need so much of code as you're just comparing memory references you can use === --> equality and sameness .
let a = {'a':1}
console.log(a === a ) // return true for same reference
console.log( {} === {}) // return false for not same reference
I don't see a good reason to do this map-filter-map combination. You can use only filter right away:
const unique = array => {
const set = new Set();
return array.filter(v => {
if (set.has(v.id)) {
return false
} else {
set.add(v.id);
return true;
}
});
};
Also if your array contains the objects that you want to compare by reference, not by their .id, you don't even need to the filtering yourself. You could just write:
const unique = array => Array.from(new Set(array));
The idea of using a Set is nice, but a Map will work even better as then you can do it all in the constructor callback:
const unique = array => [...new Map(array.map(v => [v.id, v])).values()]
// Demo:
var data = [
{ id: 1, name: "obj1" },
{ id: 3, name: "obj3" },
{ id: 1, name: "obj1" }, // dupe
{ id: 2, name: "obj2" },
{ id: 3, name: "obj3" }, // another dupe
];
console.log(unique(data));
Addendum
You speak of items that reference the same object in memory. Such a thing does not happen when your array is initialised as a plain literal, but if you assign the same object to several array entries, then you get duplicate references, like so:
const obj = { id: 1, name: "" };
const data = [obj, obj];
This is not the same thing as:
const data = [{ id: 1, name: "" }, { id: 1, name: "" }];
In the second version you have two different references in your array.
I have assumed that you want to "catch" such duplicates as well. If you only consider duplicate what is presented in the first version (shared references), then this was asked before.

_.map doesn't return an array of objects, but strings

I have an array of objects:
[{name:'john',age: 24}, {name:'arian', age: 34}]
I want to get the following array back:
[{title:'john'},{title:'arian'}]
The following code:
let tableData = {
header: [{title: 'name'}],
data: _.map(groups, group => {
return group.name
})
};
results in: ['john', 'arian']
but this code:
let tableData = {
header: [{title: 'name'}],
data: _.map(groups, group => {
return {title: group.name} // <-- this line changed
})
};
returns an array of length 0 for data. Why does this happen ? isn't it basically the same ?
Update 1
How I get groups:
const { groups } = this.props;
This is a react code.
The problem stated has a very simple solution. You are doing it right, but need little change in the code
var obj = [{name:'john',age: 24}, {name:'arian', age: 34}];
var result = _.map(obj,(value)=>{
return {name:value.name};
});
If you are expecting each member of your resultant array to be a object then you need to return that kind of object from your map, as simple as that. Either you use lodash or pure javascript version of map, answer is the same:
_.map(groups, o=>({'title': o.name}))
Or with native javascript Array map
groups.map(o=>({'title': o.name}))
Why not use native Array.prototype.map?
let data = [{name:'john',age: 24}, {name:'arian', age: 34}]
console.log(data.map( (item) => { return { title: item.name } }))

Looping through an array of objects in typescript and get a specific fails using Es6 syntax

I have several objects and i would like to get one and check a specific property
so i have
data: [{is_guest: true},{permission:'is_allowed_ip'}]
Now when i check the console.log(route.data) am getting
0:{is_guest:true},
1:{permission:'is_allowed_ip' }
and typeof route.data is an object
now i would like to get the object with is_guest:true
So i have tried
const data = Object.keys(route.data).map((index) => {
if (route.data[index].is_guest) {
return route.data[index]
}
});
console.log("route data is",data) //this still returns all the items
But the above fails returning all the objects.
How do i loop through all the objects and retrieve just only one with the is_guest key and value true
Sounds like you want Object.values, not Object.keys, and filter:
const data = Object.values(route.data).filter(e => e.is_guest);
Object.values is fairly new, but present on up-to-date Node, and entirely polyfillable.
Example:
const route = {
data: [
{is_guest: true},
{permission:'is_allowed_ip'}
]
};
const data = Object.values(route.data).filter(e => e.is_guest);
console.log(data);
Using E6:
data.filter(o => o.is_guest)
You can use the filter method.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
I added some ids into your array just to make easier to understand.
// added ids to exemplify
const data = [
{id: 1, is_guest: true},
{id: 2, permission:'is_allowed_ip'},
{id: 3, is_guest: true},
{id: 4, is_guest: false},
]
// filter results
const filtered = data.filter(item => item.is_guest)
// just to show the result
document.querySelector('.debug').innerHTML = JSON.stringify(filtered, null, 2);
<pre><code class="debug"></code></pre>

Categories