【问题标题】:JS - Filter an array of objects for duplicates of one property, and decide which object to keep based on another propertyJS - 为一个属性的重复项过滤一组对象,并根据另一个属性决定保留哪个对象
【发布时间】:2019-04-02 04:41:37
【问题描述】:

尝试通过消除具有已存在于另一个对象中的特定属性的对象(重复)来过滤对象数组。删除哪个对象的决定应该基于另一个属性。

示例: 对于可能看起来像这样的对象数组,目标是过滤所有“用户”重复项并保留具有最旧“日期”属性的对象。

const arr = [
    {user: 'Alex', date: '1540801929945'},
    {user: 'Bill', date: '1640801929946'},
    {user: 'Carl', date: '1740801929947'},
    {user: 'Alex', date: '1840801929948'},
]

预期结果:

filteredArr = [
    {user: 'Alex', date: '1540801929945'},
    {user: 'Bill', date: '1640801929946'},
    {user: 'Carl', date: '1740801929947'},
]

我管理了用于仅保留唯一对象的基本过滤。

const filteredArr = arr.reduce((unique, o) => {
    if(!unique.some(obj => obj.user === o.user) {
      unique.push(o);
    }
    return unique;
},[]);

虽然我不知道该怎么做才能在重复的情况下保留“最旧”的对象并删除最新的对象。 非常感谢你的帮助!真的很感激。

【问题讨论】:

  • 你的数据是按date排序的吗?
  • 不,很遗憾没有。这些对象在实际用例中要大得多,并且根据使用的位置以不同的方式排序......
  • 您是否只有给定的两个或更多属性?你想保留这些对象吗?
  • 是的,还有更多属性。不打算保留这些对象。

标签: javascript arrays filter duplicates javascript-objects


【解决方案1】:

将数组简化为以user 为键的对象。如果用户不在unique 对象中,或者如果它的日期比实际日期“更早”,则将其添加到对象中。使用Object.values() 将对象转换为数组。

注意:由于您的日期是字符串,所以在比较时将它们转换为数字(我使用+ operator)。

const array = [{ user: 'Alex', date: '1540801929945' }, { user: 'Bill', date: '1640801929946' }, { user: 'Carl', date: '1740801929947' }, { user: 'Alex', date: '1840801929948' }];


const filteredArray = Object.values(array.reduce((unique, o) => {
  if(!unique[o.user] || +o.date > +unique[o.user].date) unique[o.user] = o;
  
  return unique;
}, {}));

console.log(filteredArray);

【讨论】:

  • 我猜它是 (...) +o.date < +unique[o.user].date) (...) - 但除此之外它似乎有效。非常感谢您的帮助!
  • @YvonC - 我不确定您的评论指的是什么。您的对象包括date,而不是dateofpost
【解决方案2】:

Map 和单循环方法的解决方案

var array = [{ user: 'Alex', date: '1540801929945' }, { user: 'Bill', date: '1640801929946' }, { user: 'Carl', date: '1740801929947' }, { user: 'Alex', date: '1840801929948' }],
    filtered = Array.from(array
        .reduce((m, o) => !m.has(o.user) || m.get(o.user).data > o.date
            ? m.set(o.user, o)
            : m, new Map)
       .values());
      
console.log(filtered);
.as-console-wrapper { max-height: 100% !important; top: 0; }

对于排序后的数据(提前按date排序),可以使用Set进行过滤。

var array = [{ user: 'Alex', date: '1540801929945' }, { user: 'Bill', date: '1640801929946' }, { user: 'Carl', date: '1740801929947' }, { user: 'Alex', date: '1840801929948' }],
    filtered = array
        .sort(({ date: a }, { date: b }) => a - b)
        .filter((s => ({ user }) => !s.has(user) && s.add(user))(new Set));
      
console.log(filtered);
.as-console-wrapper { max-height: 100% !important; top: 0; }

【讨论】:

    【解决方案3】:

    对于O(N) 解决方案,将reduce 放入由user 索引的对象中,其值为dates - 在每次迭代中,如果user 的某些内容已经存在,则只保留最低的@987654326 @。然后,遍历对象的entries 将其转回数组:

    const arr = [
        {user: 'Alex', date: '1540801929945'},
        {user: 'Bill', date: '1640801929946'},
        {user: 'Carl', date: '1740801929947'},
        {user: 'Alex', date: '1840801929948'},
        {user: 'Carl', date: '1340801929947'},
    ];
    
    const arrByUser = arr.reduce((a, { user, date }) => {
      if (!a[user]) a[user] = date;
      else if (a[user].localeCompare(date) === 1) a[user] = date;
      return a;
    }, {});
    const output = Object.entries(arrByUser)
      .map(([user, date]) => ({ user, date }));
    console.log(output);

    【讨论】:

      【解决方案4】:

      我相信你实际上需要知道非唯一元素的索引(在你的例子中名为“Alex”的对象),然后比较它们的日期,保存旧的。

      Array.prototype.find 在这种情况下不会给你带来好处。 但是, Array.prototype.find 可能会有所帮助,因为它需要一个回调,该回调返回一个布尔值(就像'some')但它返回与你的回调匹配的元素的索引,如果没有找到这样的元素,则返回 undefined。

      试一试,不会疼的:)

      【讨论】:

        猜你喜欢
        • 2023-03-12
        • 1970-01-01
        • 1970-01-01
        • 2015-10-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-10
        • 2021-05-21
        相关资源
        最近更新 更多