简体   繁体   中英

return a filtered array of objects

I'm struggling with removing dupes from an array of objects. I have an array, storedItems:

var storedItems = [
    {text: "1", checked: false },
    {text: "2", checked: false },
    {text: "3", checked: false },
    {text: "string", checked: false }
]

etc. the text values are either strings or numeric strings. I'm ok with identifying the unique text values, either in the hash or in uniqueVals ...

filterDupes(storedItems);

function filterDupes(input) {
    var hash = {};
    var uniqueVals = [];
    input.forEach(obj => {
        hash[obj.text] = true;
    })
    var uniqueVals = Object.keys(hash); // Array
    return input.filter(function(obj, ix, arr) {
        uniqueVals.indexOf(obj.text) !== -1; // NOPE
    }) // .filter
} // filterDupes

... it's how to compare either the hash keys or uniqueVals to the input array objects, ie, what exactly I need (w/out a for loop or another forEach?) to return the filtered array, that's got me bashing my head against a wall, trying to find some version of return hash[obj.text] == obj.text; or return (hash.key === obj.text)

EDIT: fiddle here: https://jsfiddle.net/WTFoxtrot/by3nhy4n/2/

Using a combination of Array.prototype.map() and Array.prototype.filter() :

 let items = [ {text: "1", checked: false}, {text: "2", checked: false}, {text: "3", checked: false}, {text: "string", checked: false}, {text: "2", checked: false}, {text: "string", checked: false}, {text: "1", checked: false} ]; let values = items.map(it => it.text).filter((v, i, a) => a.indexOf(v) === i); console.log(values); // ["1", "2", "3", "string"] 

The filter closure (v, i, a) => a.indexOf(v) === i filters out all values that are present at any position other than the first occurrence of that value.

Using the same principles, if you want to filter the array of objects itself instead of returning a list of unique values, you can use Array.prototype.filter() with Array.prototype.find() :

 let items = [ {text: "1", checked: false}, {text: "2", checked: false}, {text: "3", checked: false}, {text: "string", checked: false}, {text: "2", checked: false}, {text: "string", checked: false}, {text: "1", checked: false} ]; let filtered = items.filter((x, i, a) => a.find(y => x.text === y.text) === x); console.log(filtered); // [{"text": "1", "checked": false}, {"text": "2", "checked": false}, {"text": "3", "checked": false}, {"text": "string", "checked": false}] 

V2: Using Set object, you migh use array indexOf the same way:

function filterDupes(input) {
  var unique = new Set();

  return input.filter((obj, ix, arr) => {
    if(!unique.has(obj.text)) {
       unique.add(obj.text);
       return true;
    }
    return false;
  })
}

If you don't want to change your function too much:

...
return input.filter((obj, ix, arr) => {
    var index = uniqueVals.indexOf(obj.text);
    if(index !== -1) {
    // Remove the element from unique array
       uniqueVals.splice(index,1);
       return true;
    }
    return false;
})

V1: Incorrect . Previously, your function is kinda incorrect. It actually does nothing. You only push the text to an array then check if the text exists in that array, again.

var storedItems = [
  {text: "1", checked: false },
  {text: "2", checked: false },
  {text: "3", checked: false },
  {text: "string", checked: false }
];

function filterDupes(input) {
  //Your previous code inside function
  ...
  return input.filter(function(obj, ix, arr) {
     return uniqueVals.indexOf(obj.text) !== -1;
  })
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM