Is it possible to use the javascript \"Set\" object to find an element with a certain key? Something like that:
let myObjects = [{\"name\":\"a\", \"value\":0
Not in that way, that would look for the specific object you're passing in, which isn't in the set.
If your starting point is an array of objects, you don't need a Set
at all, just Array.prototype.find
:
let myObjects = [{"name":"a", "value":0}, {"name":"b", "value":1},{"name":"c", "value":2}];
let found = myObjects.find(e => e.name === "a");
console.log(found);
If you already have a Set
and want to search it for a match, you can use its iterator, either directly via for-of
:
let myObjects = [{"name":"a", "value":0}, {"name":"b", "value":1},{"name":"c", "value":2}];
let mySet = new Set(myObjects);
let found = undefined; // the `= undefined` is just for emphasis; that's the default value it would have without an initializer
for (const e of mySet) {
if (e.name === "a") {
found = e;
break;
}
}
console.log(found);
...or indirectly via Array.from
to (re)create (the)an array, and then use find
:
let myObjects = [{"name":"a", "value":0}, {"name":"b", "value":1},{"name":"c", "value":2}];
let mySet = new Set(myObjects);
let found = Array.from(mySet).find(e => e.name === "a");
console.log(found);
If it's something you need to do often, you might give yourself a utility function for it:
const setFind = (set, cb) => {
for (const e of set) {
if (cb(e)) {
return e;
}
}
return undefined; // undefined` just for emphasis, `return;`
// would do effectively th same thing, as
// indeed would just not having a `return`
// at at all
}
let myObjects = [{"name":"a", "value":0}, {"name":"b", "value":1},{"name":"c", "value":2}];
let mySet = new Set(myObjects);
let found = setFind(mySet, e => e.name === "a");
console.log(found);
You could even put that on Set.prototype
(making sure it's non-enumerable), but beware of conflicting with future additions to Set
(for instance, I wouldn't be at all surprised if Set.prototype
got a find
method at some point).
Short answer - no. Set.has
operates on object equality, and each object in the list is unique - so when you pass a new object to .has
it will not return true
, even if it has the same keys and values.
You could always filter the original list, and if the resulting list has a length greater than zero, your object will be contained within.
const containsObjectWithName = ({ name }) =>
!!myObjects
.filter((obj) => obj.name === name)
.length;
containsObjectWithName({ name: 'a' }); // true
If you want your solution to be performant, use Map
instead of Set
.
If your Set
is not that big you can go with T.J. Crowder solution and convert Set
to Array
then filter and vice versa.
let myObjects = [['a',{"name":"a", "value":0}], ['b',{"name":"b", "value":1}],['c',{"name":"c", "value":2}]];
let myMap = new Map(myObjects);
console.log(myMap.has('a'));
If you want to do this with a Set, then the object you're searching for has to be the same object that was added, not an anonymous object.
So, you could achieve what you're looking for if it was set up like this:
let myObject = {"name": "a", "value": 0};
let set = new Set([myObject]);
console.log(set.has(myObject));
This is because set.has()
uses SameValueZero()
under the hood.
Here is the spec for set.has()
: http://www.ecma-international.org/ecma-262/6.0/#sec-set.prototype.has
And for SameValueZero()
: http://www.ecma-international.org/ecma-262/6.0/#sec-samevaluezero
Actually a response to Efficiently find an item in a Set but they've closed it as a duplicate #ftw
An alternative approach:
class ArraySet extends Set {
find(predicate) {
for(var x of this)
if (predicate(x)) return x;
return undefined;
},
... other Array.prototype stuff here
}
const things = new ArraySet([
{ x: 1 },
{ y: 2 }
]);
const found = things.find(item => item.y === 2);
You may just want a Set of names:
let myObjects = [{"name":"a", "value":0}, {"name":"b", "value":1},{"name":"c", "value":2}];
let map = new Set(myObjects.map(el=>el.name));
console.log(map.has("a"));
If you want to get an object by name,thats what a Map is for:
let myObjects = [{"name":"a", "value":0}, {"name":"b", "value":1},{"name":"c", "value":2}];
let map = new Map(myObjects.map(el=>[el.name,el]));
console.log(map.get("a"));