繁体   English   中英

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

[英]javascript - find unique objects in array based on multiple properties

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

来源:

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 中查看并能够找到基于一个属性( 按属性创建唯一对象数组)过滤的答案,但找不到可以基于 2 个属性执行的操作。

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

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

同样没有(错误)使用Array#filter thisArg

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

使用组合键和 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()); }

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

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

像大多数答案一样,转换为键为值串联的映射,然后返回到数组。 这个使用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; }, {})); }

嘿你可以用这个方法

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

根据其字段的任意数组提取唯一对象数组的另几种变体,对性能进行了测试:

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

 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"}, ] */

1.5% 在性能上落后于第一个

 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"} ] */

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

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

您可以使用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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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