javascript - find unique objects in array based on

2020-02-04 20:48发布

问题:

I need to find unique objects from array based on 2 properties as below. When "class" and "fare" match, I need to pull out unique values and get them in results array.

Source:

var arr = [{class:"second", fare: "a"}, 
 {class:"second", fare: "b"},
 {class:"first", fare: "a"},
 {class:"first", fare: "a"},
 {class:"second", fare: "a"},
 {class:"first", fare: "c"}
]

Expected result:

var result = [{class:"second", fare: "a"},
 {class:"second", fare: "b"},
 {class:"first", fare: "a"},
 {class:"first", fare: "c"}
]

I looked over in SO and was able to find answer which is filtered based on one property (Create array of unique objects by property), but couldn't find which could do based on 2 properties.

回答1:

You could build a combined key for the hash table and filter the given array.

var arr = [{ class: "second", fare: "a" }, { class: "second", fare: "b" }, { class: "first", fare: "a" }, { class: "first", fare: "a" }, { class: "second", fare: "a" }, { class: "first", fare: "c" }],
    result = arr.filter(function (a) {
        var key = a.class + '|' + a.fare;
        if (!this[key]) {
            this[key] = true;
            return true;
        }
    }, Object.create(null));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

The same without (mis)using thisArg of Array#filter.

var array = [{ class: "second", fare: "a" }, { class: "second", fare: "b" }, { class: "first", fare: "a" }, { class: "first", fare: "a" }, { class: "second", fare: "a" }, { class: "first", fare: "c" }],
    seen = Object.create(null),
    result = array.filter(o => {
        var key = ['class', 'fare'].map(k => o[k]).join('|');
        if (!seen[key]) {
            seen[key] = true;
            return true;
        }
    });

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }



回答2:

Using a combined key and a Map

const array = [
 { class: "second", fare: "a" }, 
 { class: "second", fare: "b" }, 
 { class: "first", fare: "a" }, 
 { class: "first", fare: "a" }, 
 { class: "second", fare: "a" }, 
 { class: "first", fare: "c" }
];

console.log(unique(array, ['class', 'fare']));

function unique(arr, keyProps) {
 const kvArray = arr.map(entry => {
  const key = keyProps.map(k => entry[k]).join('|');
  return [key, entry];
 });
 const map = new Map(kvArray);
 return Array.from(map.values());
}



回答3:

You can use forEach to loop and filter or find array property to find if the element exist in array

var arr = [{
      class: "second",
      fare: "a"
    }, {
      class: "second",
      fare: "b"
    }, {
      class: "first",
      fare: "a"
    }, {
      class: "first",
      fare: "a"
    }, {
      class: "second",
      fare: "a"
    }, {
      class: "first",
      fare: "c"
    }]
    var _unArray = []; // new array without duplicate
    arr.forEach(function(item) { // loop through array which contain duplicate
      // if item is not found in _unArray it will return empty array
       var isPresent = _unArray.filter(function(elem) {
        return elem.class === item.class && elem.fare === item.fare
      })
      if (isPresent.length == 0) { 
        _unArray.push(item)
      }
    })
    console.log(_unArray)

JSFIDDLE



回答4:

Like most answers, convert to a map with keys being a concatenation of the values, then back to an array. This one uses reduce.

const array = [
  { class: "second", fare: "a" }, 
  { class: "second", fare: "b" }, 
  { class: "first", fare: "a" }, 
  { class: "first", fare: "a" }, 
  { class: "second", fare: "a" }, 
  { class: "first", fare: "c" }
];

console.log(unique(array, ['class', 'fare']));

function unique(arr, keyProps) {
  return Object.values(arr.reduce((uniqueMap, entry) => {
    const key = keyProps.map(k => entry[k]).join('|');
    if (!(key in uniqueMap)) uniqueMap[key] = entry;
    return uniqueMap;
  }, {}));     
}  



回答5:

function unique(arr, keyProps) {
 const kvArray = arr.map(entry => { // entry = {class: "second", fare: "a"}

  // keyProps = ["class", "fare"]
  // k="class"; entry[k]="second";
  // k="fare"; entry[k]="a"
  // keyProps.map(k => entry[k])=["second","a"];
  // .join("|")="second|a";
  const key = keyProps.map(k => entry[k]).join('|'); // key = "second|a"
  return [key, entry]; // ["second|a",{"class":"second","fare":"a"}]
 });

 // kvArray = [["second|a",{"class":"second","fare":"a"}],["second|b", 
 //           {"class":"second","fare":"b"}],["first|a",{"class":"first","fare":"a"}], 
 //           ["first|a",{"class":"first","fare":"a"}],["second|a", 
 //           {"class":"second","fare":"a"}],["first|c",{"class":"first","fare":"c"}]]
 const map = new Map(kvArray); // this will remove duplicate entry with same key. 
 return Array.from(map.values()); // convert back to array from all entry's value
}