Javascript search for an object key in a set

前端 未结 6 738
太阳男子
太阳男子 2021-01-14 09:46

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         


        
相关标签:
6条回答
  • 2021-01-14 09:54

    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).

    0 讨论(0)
  • 2021-01-14 09:55

    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
    
    0 讨论(0)
  • 2021-01-14 09:55

    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'));
    
    
    0 讨论(0)
  • 2021-01-14 09:56

    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

    0 讨论(0)
  • 2021-01-14 09:56

    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);
    
    
    0 讨论(0)
  • 2021-01-14 09:57

    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"));
    
    0 讨论(0)
提交回复
热议问题