remove objects from array by object property

前端 未结 13 2713
抹茶落季
抹茶落季 2020-11-22 17:40
var listToDelete = [\'abc\', \'efg\'];

var arrayOfObjects = [{id:\'abc\',name:\'oh\'}, // delete me
                      {id:\'efg\',name:\'em\'}, // delete me
            


        
相关标签:
13条回答
  • 2020-11-22 17:44

    With lodash/underscore:

    If you want to modify the existing array itself, then we have to use splice. Here is the little better/readable way using findWhere of underscore/lodash:

    var items= [{id:'abc',name:'oh'}, // delete me
                      {id:'efg',name:'em'},
                      {id:'hij',name:'ge'}];
    
    items.splice(_.indexOf(items, _.findWhere(items, { id : "abc"})), 1);
    

    With ES5 or higher

    (without lodash/underscore)

    With ES5 onwards we have findIndex method on array, so its easy without lodash/underscore

    items.splice(items.findIndex(function(i){
        return i.id === "abc";
    }), 1);
    

    (ES5 is supported in almost all morden browsers)

    About findIndex, and its Browser compatibility

    0 讨论(0)
  • 2020-11-22 17:44

    To delete an object by it's id in given array;

    const hero = [{'id' : 1, 'name' : 'hero1'}, {'id': 2, 'name' : 'hero2'}];
    //remove hero1
    const updatedHero = hero.filter(item => item.id !== 1);
    
    0 讨论(0)
  • 2020-11-22 17:47

    I assume you used splice something like this?

    for (var i = 0; i < arrayOfObjects.length; i++) {
        var obj = arrayOfObjects[i];
    
        if (listToDelete.indexOf(obj.id) !== -1) {
            arrayOfObjects.splice(i, 1);
        }
    }
    

    All you need to do to fix the bug is decrement i for the next time around, then (and looping backwards is also an option):

    for (var i = 0; i < arrayOfObjects.length; i++) {
        var obj = arrayOfObjects[i];
    
        if (listToDelete.indexOf(obj.id) !== -1) {
            arrayOfObjects.splice(i, 1);
            i--;
        }
    }

    To avoid linear-time deletions, you can write array elements you want to keep over the array:

    var end = 0;
    
    for (var i = 0; i < arrayOfObjects.length; i++) {
        var obj = arrayOfObjects[i];
    
        if (listToDelete.indexOf(obj.id) === -1) {
            arrayOfObjects[end++] = obj;
        }
    }
    
    arrayOfObjects.length = end;
    

    and to avoid linear-time lookups in a modern runtime, you can use a hash set:

    const setToDelete = new Set(listToDelete);
    let end = 0;
    
    for (let i = 0; i < arrayOfObjects.length; i++) {
        const obj = arrayOfObjects[i];
    
        if (setToDelete.has(obj.id)) {
            arrayOfObjects[end++] = obj;
        }
    }
    
    arrayOfObjects.length = end;
    

    which can be wrapped up in a nice function:

    const filterInPlace = (array, predicate) => {
        let end = 0;
    
        for (let i = 0; i < array.length; i++) {
            const obj = array[i];
    
            if (predicate(obj)) {
                array[end++] = obj;
            }
        }
    
        array.length = end;
    };
    
    const toDelete = new Set(['abc', 'efg']);
    
    const arrayOfObjects = [{id: 'abc', name: 'oh'},
                            {id: 'efg', name: 'em'},
                            {id: 'hij', name: 'ge'}];
    
    filterInPlace(arrayOfObjects, obj => !toDelete.has(obj.id));
    console.log(arrayOfObjects);

    If you don’t need to do it in place, that’s Array#filter:

    const toDelete = new Set(['abc', 'efg']);
    const newArray = arrayOfObjects.filter(obj => !toDelete.has(obj.id));
    
    0 讨论(0)
  • 2020-11-22 17:47

    Only native JavaScript please.

    As an alternative, more "functional" solution, working on ECMAScript 5, you could use:

    var listToDelete = ['abc', 'efg'];
    var arrayOfObjects = [{id:'abc',name:'oh'}, // delete me
                          {id:'efg',name:'em'}, // delete me
                          {id:'hij',name:'ge'}]; // all that should remain
    
    arrayOfObjects.reduceRight(function(acc, obj, idx) {
        if (listToDelete.indexOf(obj.id) > -1)
            arrayOfObjects.splice(idx,1);
    }, 0); // initial value set to avoid issues with the first item and
           // when the array is empty.
    
    console.log(arrayOfObjects);
    [ { id: 'hij', name: 'ge' } ]
    

    According to the definition of 'Array.prototype.reduceRight' in ECMA-262:

    reduceRight does not directly mutate the object on which it is called but the object may be mutated by the calls to callbackfn.

    So this is a valid usage of reduceRight.

    0 讨论(0)
  • 2020-11-22 17:48

    with filter & indexOf

    withLodash = _.filter(arrayOfObjects, (obj) => (listToDelete.indexOf(obj.id) === -1));
    withoutLodash = arrayOfObjects.filter(obj => listToDelete.indexOf(obj.id) === -1);
    

    with filter & includes

    withLodash = _.filter(arrayOfObjects, (obj) => (!listToDelete.includes(obj.id)))
    withoutLodash = arrayOfObjects.filter(obj => !listToDelete.includes(obj.id));
    
    0 讨论(0)
  • 2020-11-22 17:53

    Check this out using Set and ES6 filter.

      let result = arrayOfObjects.filter( el => (-1 == listToDelete.indexOf(el.id)) );
      console.log(result);
    

    Here is JsFiddle: https://jsfiddle.net/jsq0a0p1/1/

    0 讨论(0)
提交回复
热议问题