javascript - 基于多个属性在数组中查找唯一对象

时间:2016-07-27 12:57:30

标签: javascript arrays

我需要根据以下2个属性从数组中找到唯一对象。当" class"和"票价"匹配,我需要提取唯一值并将它们放在结果数组中。

来源:

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 result = [{class:"second", fare: "a"},
 {class:"second", fare: "b"},
 {class:"first", fare: "a"},
 {class:"first", fare: "c"}
]

我查看了SO,并且能够找到基于一个属性(Create array of unique objects by property)过滤的答案,但无法找到基于2个属性可以做的事情。

9 个答案:

答案 0 :(得分:11)

您可以为哈希表构建一个组合键,过滤给定数组。

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

答案 1 :(得分:2)

使用组合键和地图



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());
}




答案 2 :(得分:1)

解决上述问题的简便方法,尽管它是一个非常老的线程,并且也许将来会对某人有所帮助。

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" }
];

const uniqueObjects = new Set();

array.forEach(arr => uniqueObjects.add(JSON.stringify(arr)));

console.log(uniqueObjects.entries())

答案 3 :(得分:1)

基于对象字段的任意数组提取对象唯一数组的另一种方法,经过性能测试:

在性能上总是最好的,使用递归函数

const 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"}
]
 
const getUniqArrBy = (props = [], arrInp = [{}], objTmp={}, arrTmp=[]) => {
  if (arrInp.length > 0) {
    const lastItem = arrInp[arrInp.length -1]
    const propStr = props.reduce((res, item) => (`${res}${lastItem[item]}`), '')
    if (!objTmp[propStr]) {
      objTmp[propStr] = true
      arrTmp=[...arrTmp, lastItem]
    }
    arrInp.pop()
    return getUniqArrBy(props, arrInp, objTmp, arrTmp)
  }
  return arrTmp
}

const uniq = getUniqArrBy(['class', 'fare'], arr)

console.info({ uniq })
/*
    [
      {class: "first", fare: "c"},
      {class: "second", fare: "a"},
      {class: "first", fare: "a"},
      {class: "second", fare: "b"},
    ]
*/

在性能方面落后于第一名

const 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"}
]
 
const getUniqArrBy = (props = [], arrInp = [{}]) => {
  const objKey = {}
  return arrInp.reduce((res, item) => {
    const valStr = props.reduce((res, prop) => `${res}${item[prop]}`, '')
    if(objKey[valStr]) return res
    objKey[valStr] = item
    return [...res, item]
  }, [])
}

const uniq = getUniqArrBy(['class', 'fare'], arr)

console.info({ uniq })
/*
    [
     {class:"second", fare: "a"},
     {class:"second", fare: "b"},
     {class:"first", fare: "a"},
     {class:"first", fare: "c"}
    ]
*/

在表现上接近拳头两个

const 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"}
]

const getUniqArrBy = (props = [], arr = [{}]) => arr.filter((e, i) =>
   arr.findIndex(a => {
    let aKey = '', eKey = ''
    props.forEach(prop => (aKey = `${aKey}${a[prop]}`, eKey = `${eKey}${e[prop]}`))
    return aKey === eKey
}) === i)

const uniq = getUniqArrBy(['class', 'fare'], arr)

console.info({ uniq })
/*
[
 {class:"second", fare: "a"},
 {class:"second", fare: "b"},
 {class:"first", fare: "a"},
 {class:"first", fare: "c"}
]
*/

在Firefox中运行迅速,在Chrome和Edge中-并非如此,简而言之

const 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"}
]
 
const getUniqArrBy = (props = [], arrInp = [{}]) => {
  return Object.values(arrInp.reduce((res, item) => {
    const keyComb = props.reduce((res, prop) => `${res}${item[prop]}`, '')
    return { ...res, [keyComb]: item }
  }, []))
}

const uniq = getUniqArrBy(['class', 'fare'], arr)

console.info({ uniq })
/*
    [
     {class:"second", fare: "a"},
     {class:"second", fare: "b"},
     {class:"first", fare: "a"},
     {class:"first", fare: "c"}
    ]
*/

缩写,但通常比第一个慢5-8%

const 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"}
]

const getUniqArrBy = (props = [], arr = [{}]) => arr.filter((e, i) =>
   arr.findIndex(a => props.reduce((res, prop) => `${res}${a[prop]}`, '') ===
   props.reduce((res, prop) => `${res}${e[prop]}`, '')) === i)

const uniq = getUniqArrBy(['class', 'fare'], arr)

console.info({ uniq })
/*
    [
     {class:"second", fare: "a"},
     {class:"second", fare: "b"},
     {class:"first", fare: "a"},
     {class:"first", fare: "c"}
    ]
*/

在不同的浏览器中,平均速度比第一个慢9-18%

const 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"}
]
 
const getUniqArrBy = (props = [], arrInp = [{}]) => {
  const objKey = arrInp.reduce((res, item) => {
    const valStr = props.reduce((res, prop) => `${res}${item[prop]}`, '')
    return {...res, [valStr]: item }
  }, {})
  return Object.keys(objKey).map(item => objKey[item])
}

const uniq = getUniqArrBy(['class', 'fare'], arr)

console.info({ uniq })
/*
    [
     {class:"second", fare: "a"},
     {class:"second", fare: "b"},
     {class:"first", fare: "a"},
     {class:"first", fare: "c"}
    ]
*/

答案 4 :(得分:1)

根据对象字段的任意数组提取对象的唯一数组的另一种形式:

    const arr = [
      { class: 'second', fare: 'a', weight: 12 },
      { class: 'second', fare: 'b', weight: 10 },
      { class: 'first', fare: 'a', weight: 15 },
      { class: 'first', fare: 'a', weight: 17 },
      { class: 'second', fare: 'a', weight: 12 },
      { class: 'first', fare: 'c', weight: 30 },
      { class: 'second', fare: 'b', weight: 22 },
    ]

    const getUniqArrBy = (props = [], arrInp = [{}]) => {
      const obj = {}
      let result = []
      arrInp.forEach((item, index) => {
            let key = ''
            props.forEach(prop => (key += item[prop]))
            obj[key] = index
      })
      const keys = Object.keys(obj)
      keys.forEach(key => (result = [...result, arrInp[obj[key]]]))
      return result
    }

    const uniq = getUniqArrBy(['class', 'fare'], arr)

    console.info({ uniq })

答案 5 :(得分:0)

您可以使用forEach循环和filterfind数组属性来查找元素是否存在于数组中

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

答案 6 :(得分:0)

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
}

答案 7 :(得分:0)

与大多数答案一样,将其转换为键,键为值的串联,然后返回数组。此人使用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;
  }, {}));     
}  

答案 8 :(得分:0)

嘿,您可以使用此方法

const unique = (arr, props = []) => [...new Map(arr.map(entry => [props.map(k => entry[k]).join('|'), entry])).values()];

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',
    },
];

const newArr = unique(array, ['class', 'fare']);

console.log(newArr) // [{ class: 'second', fare: 'a' }, { class: 'second', fare: 'b' }, { class: 'first', fare: 'a' }, { class: 'first', fare: 'c' }]