【问题标题】:How to get unique values from Object Array Javascript如何从对象数组 Javascript 中获取唯一值
【发布时间】:2019-01-03 09:00:05
【问题描述】:

所以我有一个对象数组如下:

var array = [
    {name:"Joe", date:'2018-07-01', amt:250 },
    {name:"Mars", date:'2018-07-01', amt:250 },
    {name:"Joe", date:'2018-07-02', amt:250 },
    {name:"Saturn", date:'2018-07-01', amt:250 },
    {name:"Joe", date:'2018-07-02', amt:250 },
    {name:"Jupiter", date:'2018-07-01', amt:250 },
]

我想根据name、amount 和date 是否重复来过滤数据。 这个甚至不过滤重复的名称。

var unique = array.filter((v, i, a) =>{ return a.indexOf(v) === i});

如何根据name、amount 和date 过滤此重复项?

【问题讨论】:

  • 不清楚:曾经有 2 个项目具有相同的 name 值但不同的 date 和 amt。您是否需要排除它们?
  • 最简单的解决方案是将该数组唯一化3次:array = _.uniqBy(array, 'name'); array = _.uniqBy(array, 'date'); array = _.uniqBy(array, 'amt'); 但效率不高
  • @skyboyer NO.仅当 3 个值重复时。
  • @ramj 然后通过答案检查(第二种解决方案)_.uniq(array);,只有你需要 lodash 库
  • @Sylwester 不正确 - indexOf 函数在传递对象时只会比较对象的 reference 以在数组中完全匹配,并且不会进行深度比较在其中的键或值上。

标签: javascript arrays duplicates


【解决方案1】:

试试这个代码,它只返回唯一的对象。

var data = [
{name:"Joe", date:'2018-07-01', amt:250 },
{name:"Mars", date:'2018-07-01', amt:250 },
{name:"Joe", date:'2018-07-02', amt:250 },
{name:"Saturn", date:'2018-07-01', amt:250 },
{name:"Joe", date:'2018-07-02', amt:250 },
{name:"Jupiter", date:'2018-07-01', amt:250 },
]
var resArr = [];
data.filter(function(item){
  var i = resArr.findIndex(x => (x.name == item.name && x.date == item.date && x.amt == item.amt));
  if(i <= -1){
        resArr.push(item);
  }
  return null;
});
console.log(resArr)

如果这不是你要找的,请告诉我。

【讨论】:

  • 谢谢。更简单、更清洁。
  • 欢迎您,先生。如果这是您想要的解决方案,那么请将其标记为正确。 :)
【解决方案2】:

试试这个:

     var array = [
        {name:"Joe", date:'2018-07-01', amt:250 },
        {name:"Mars", date:'2018-07-01', amt:250 },
        {name:"Joe", date:'2018-07-02', amt:250 },
        {name:"Saturn", date:'2018-07-01', amt:250 },
        {name:"Joe", date:'2018-07-02', amt:250 },
        {name:"Jupiter", date:'2018-07-01', amt:250 },
    ]

    var unique = Array.from(new Set(array.map(JSON.stringify))).map(JSON.parse);
    
    console.log(unique)

【讨论】:

  • 很好的解决方案,但它仅在对象相同时才有效(对象的所有值都相同)。
  • 如果数组中的元素之一是{amt:250,name:"Jupiter",date"2018-07-01"}(即,相同的数据以不同的属性顺序)则不起作用
【解决方案3】:

var array = [
    {name:"Joe", date:'2018-07-01', amt:250 },
    {name:"Mars", date:'2018-07-01', amt:250 },
    {name:"Joe", date:'2018-07-02', amt:250 },
    {name:"Saturn", date:'2018-07-01', amt:250 },
    {name:"Joe", date:'2018-07-02', amt:250 },
    {name:"Jupiter", date:'2018-07-01', amt:250 },
]

let answer = [];

array.forEach(x => {
  if(!answer.some(y => JSON.stringify(y) === JSON.stringify(x))){
    answer.push(x)
  }
})

console.log(answer)

另一种解决方案。你可以使用 Array#forEach、Array#some、JSON.stringify 来实现你想要的

【讨论】:

  • 除非数组中的元素之一是{amt:250,name:"Jupiter",date"2018-07-01"}(即相同的数据以不同的属性顺序)
【解决方案4】:

Array.prototype.filter 和 Set 的解决方案:

var data=[{name:"Joe",date:"2018-07-01",amt:250},{name:"Mars",date:"2018-07-01",amt:250},{name:"Joe",date:"2018-07-02",amt:250},{name:"Saturn",date:"2018-07-01",amt:250},{name:"Joe",date:"2018-07-02",amt:250},{name:"Jupiter",date:"2018-07-01",amt:250}];

var filtered = data.filter(function({name, date, amt}) {
    var key = `${name}${date}${amt}`;
    return !this.has(key) && this.add(key);
}, new Set);

console.log(filtered);

【讨论】:

  • 非常优雅地使用回调 thisarg
【解决方案5】:

你可以使用https://lodash.com/库

如果您只需要一个值的唯一性:

array = _.uniqWith(array, function(arrVal, othVal) {
    return arrVal.name == othVal.name || arrVal.date == othVal.date || arrVal.amt == othVal.amt;
}) 
console.log(array);

如果您需要通过完整对象删除唯一性:

array = _.uniq(array);
console.log(array);

【讨论】:

  • @dark_gf _.uniqWith 来自什么或哪里?
  • 是的,它是一个 lodash 库 lodash.com 。有很多类似的库。我修改了答案
【解决方案6】:

此代码在您的控制台中显示重复项。如果要打印除重复项以外的所有内容,请将return true 与return false 和return false 与return true 交换。

var orders = [
    {name:"Joe", date:'2018-07-01', amt:250 },
    {name:"Mars", date:'2018-07-01', amt:250 },
    {name:"Joe", date:'2018-07-02', amt:250 },
    {name:"Saturn", date:'2018-07-01', amt:250 },
    {name:"Joe", date:'2018-07-02', amt:250 },
    {name:"Jupiter", date:'2018-07-01', amt:250 },
];

orders = orders.filter( (order, index) => {

  // iterate over the array to check for possible duplicates
  // iterating over the items we already checked isn't necessary so we start at index+1
  for( let i = index+1; i<orders.length; i++ ){
    if(
      orders[i].name === order.name
      && orders[i].date === order.date
      && orders[i].amt === order.amt
    ){
     // just logging this stuff so you can see what happens
     console.log( `${index} is a duplicate of ${i}` );
     // if a duplicate is found return true to the filter function
     return true; 
    }
  }
  // if no duplication is found return false to the filter function
  return false;
  
}); // end filter 

// log the result to the console
console.log(orders);

【讨论】:

    【解决方案7】:

    给定你的原始数组:

    var array = [
        {name:"Joe", date:'2018-07-01', amt:250 },
        {name:"Mars", date:'2018-07-01', amt:250 },
        {name:"Joe", date:'2018-07-02', amt:250 },
        {name:"Saturn", date:'2018-07-01', amt:250 },
        {name:"Joe", date:'2018-07-02', amt:250 },
        {name:"Jupiter", date:'2018-07-01', amt:250 }
    ];
    

    您需要一个函数来确定要检查的标准,以使您的对象与其他对象具有可比性。

    更新

    这样的函数可以是hash function,您应该编写它来创建唯一键来识别您的对象并相互比较。

    如果使用具有相同组合键的对象调用正确的哈希函数,则应该返回相同的值。

    在您的情况下,当 2 个对象的 name、date 和 amount 具有相同的值时,散列函数应该返回相同的值。

    所以你可以直接比较哈希值而不是对象。

    在您要求的情况下,所有值都与过滤器一致,这是此类函数的一个非常简单的示例,它不是正确的“哈希”,因为输出是可变的(应该产生一个 固定长度值代替):

    function objectHash (obj) {
        return Object.values(obj).reduce((a, b) => {
            a += b;
            return a;
        }, '');
    }
    

    现在,您现在可以轻松正确地比较数组中的项目以过滤重复项。

    var arrayMap = array.reduce((acc, item) => {
        var hash = objectHash(item);
        if (typeof acc[hash] === 'undefined') {
            acc[hash] = Object.assign({}, item);
        }
        return acc;
    }, {})
    

    然后你有一个具有唯一键值的对象,并返回你的唯一数组:

     var uniqueArray = Object.values(arrayMap);
    

    现在你有你的数据了。

    【讨论】:

    • “哈希”函数可能会发生冲突。您所描述的不是哈希函数,因为您需要唯一性。
    • 你说得对,它不是“散列”函数,因为散列是根据输入中给定的可变长度值计算得出的恒定长度输出值。我使用“哈希”这个词只是为了说明从对象计算的值。
    • 恒定长度也不是散列的先决条件(在您的代码中甚至不是这样,所谓的“散列”可能是可变长度的)。请修正你的答案,因为它是非常具有误导性的。
    • 我写的是一个简单的例子,在这种特殊情况下不需要真正的哈希算法来实现结果。关键是有助于理解有助于比较函数的对象的字符串唯一表示的概念。当我写“常数”时,我说“固定”。
    • 我不反对这项技术,我反对您将其称为哈希,因为真正的哈希算法正是不是生成唯一密钥的正确方法,除非您'有一个非常耐碰撞的算法(例如 SHA-1 或更好的算法),但这对于这个用例来说是多余的。
    【解决方案8】:

    这需要通过过滤数组来实现,以便仅包含原始数组中第一个匹配条目(别名为a)与当前正在检查的元素具有相同index 的元素:

    let uniq = array.filter(({name, date, amount}, index, a) =>
                   a.findIndex(e => name === e.name &&
                                    date === e.date &&
                                  amount === e.amount) === index);
    

    【讨论】:

    【解决方案9】:

    我会这样做:

    const array = [
        {name:"Joe", date:'2018-07-01', amt:250 },
        {name:"Mars", date:'2018-07-01', amt:250 },
        {name:"Joe", date:'2018-07-02', amt:250 },
        {name:"Saturn", date:'2018-07-01', amt:250 },
        {name:"Joe", date:'2018-07-02', amt:250 },
        {name:"Jupiter", date:'2018-07-01', amt:250 },
    ];
    
    function uniqueBy(arr, key, $some = false) {
      if (key instanceof Array) {
        if ($some) {
          return key.reduce(uniqueBy, arr);
        } else {
          const fnUnique = (obj) =>
            key.reduce((a, k) => `${a}-${obj[k]}`, '');
          return Object.values(arr.reduce((a, v) => {
              const key = fnUnique(v)
              return a[key] === undefined ? (a[key] = v, a) : a;
          }, {}));
      }
    }
    return Object.values(arr.reduce((a, v) => (a[v[key]] === undefined ? (a[v[key]] = v, a) : a), {}));
    }
    
    // print unique objects based on the given fields
    console.log(uniqueBy(array, ['name', 'date', 'amt']));
    
    // print unique objects based on any unique value in any given fields
    console.log(uniqueBy(array, ['name', 'date', 'amt'], true));

    这只关心给定的字段,因此如果您有重复的对象但有其他不感兴趣的属性,您可以获得较少的结果。

    将true 作为第三个参数传递会将字段本身视为唯一的。因此,结果只会包含所有字段都是唯一的对象,因此由于数量相同,您最终会得到一个元素。

    【讨论】:

    • 但是火星、土星和木星在哪里?我的预期输出是这样的:const array = [ {name:"Joe", date:'2018-07-01', amt:250 }, {name:"Mars", date:'2018-07-01', amt:250 }, {name:"Joe", date:'2018-07-02', amt:250 }, {name:"Saturn", date:'2018-07-01', amt:250 }, {name:"Jupiter", date:'2018-07-01', amt:250 }, ]; Removing one {name:"Joe", date:'2018-07-02', amt:250 },` 因为它是重复条目。
    • @ramj 他们走了,因为他们的数量相同。我想你想删除那些有任何列重复的列,因此结果只会有那些具有唯一名称、唯一日期和唯一值的列。我已经为你想要的那个添加了支持,但是你真的应该在你的问题中添加预期的结果。
    【解决方案10】:

    使用名称过滤唯一 ID 的代码

    {id: 555, name: "Sales", person: "Jordan" },
    {id: 555, name: "Sales", person: "Bob" },
    {id: 555, name: "Sales", person: "John" },
    {id: 777, name: "Accounts Payable", person: "Rhoda" },
    {id: 777, name: "Accounts Payable", person: "Harry" },
    {id: 888, name: "IT", person: "Joe" },
    {id: 888, name: "IT", person: "Jake" },
    ];
    var unique = [];
    var tempArr = [];
    data.forEach((value, index) => {
        if (unique.indexOf(value.name) === -1) {
            unique.push(value.name);
            tempArr.push(value.id);
        }
    });
    console.log('Unique Ids', tempArr);
    

    【讨论】:

      猜你喜欢
      • 2019-10-20
      • 1970-01-01
      • 2020-07-14
      • 2020-11-13
      • 2019-06-21
      • 1970-01-01
      • 1970-01-01
      • 2021-12-30
      相关资源
      最近更新 更多