过滤器列表 - 根据计数键删除两个重复项中的较小项

时间:2021-04-17 20:44:30

In this problem I have a grocery list that I want to filter by removing duplicates and keeping only the duplicate with the higher count. Then also keeping items that are not duplicates. I ended up making this work through sheer programming by coincidence and would like to learn A better way to solve this problem. I commented my code below to share what's going on and my thought process. If anyone has a better way to solve this problem, I'd love to learn it.

在这个问题中,我有一个购物清单,我希望通过删除重复过滤并仅保留具有较高计数的副本来过滤。然后还保留不重复的项目。我最终通过巧合编程完成了这项工作,并希望学习更好的方法来解决这个问题。我评论下面的代码,分享正在发生的事情和我的思考过程。如果有人有更好的方法来解决这个问题,我很乐意学习它。

var groceryList = [
  {
    item: "Bananas",
    count: 4
  },
  {
    item: "Bananas",
    count: 3
  },
  {
    item: "Brussel Sprouts",
    count: 2
  },
  {
    item: "Bacon",
    count: 100
  },
  {
    item: "Beans",
    count: 19
  },
  {
    item: "Beans",
    count: 5
  }
]

const seen = {}
const newList = []
var removeDups = []
const list = groceryList.map(function(item) {
  // if we haven't this item before (via check on item name) push it into seen object
  // also push it to newList array
  if (!seen[item.item]) {
    seen[item.item] = item
    newList.push(item)
  }
  // if we have seen the item during iteration...
  else if (seen[item.item]) {
    // remove it from the newList array
    removeDups = newList.filter(function(listItem) {
      if (listItem.item == item.item) {
        console.log('matched');
      } else {
        return true
      }
    })

    // and push in the item with the higher count
    if (seen[item.item].count > item.count) {
      removeDups.push(seen[item.item])
    } else {
      removeDups.push(item)
    }
  }
})

console.log(removeDups);

4 个解决方案

#1


2  

You can use reduce to concisely transform an array into another (or into an object) when the input items and output items aren't necessarily one-to-one:

当输入项和输出项不一定是一对一时,您可以使用reduce将数组简洁地转换为另一个(或转换为对象):

var groceryList=[{item:"Bananas",count:4},{item:"Bananas",count:3},{item:"Brussel Sprouts",count:2},{item:"Bacon",count:100},{item:"Beans",count:19},{item:"Beans",count:5}]
const filteredListObj = groceryList.reduce((a, { item, count }) => {
  // this is a new item, or a duplicate with a greater quantity:
  if (!a[item] || a[item].count < count) a[item] = { item, count };
  return a;
}, {});
const filteredList = Object.values(filteredListObj);
console.log(filteredList);

#2


1  

You could take a hash table and use the original objects without creating new ones.

您可以使用哈希表并使用原始对象而无需创建新对象。

var groceryList = [ { item: "Bananas", count: 3 }, { item: "Bananas", count: 4 }, { item: "Brussel Sprouts", count: 2 }, { item: "Bacon", count: 100 }, { item: "Beans", count: 19 }, { item: "Beans", count: 5 }],
    hash = Object.create(null),
    uniques = groceryList.reduce((r, o) => {
        if (!(o.item in hash)) {
            hash[o.item] = r.push(o) - 1;
        }
        if (r[hash[o.item]].count < o.count) {
            r[hash[o.item]] = o;
        }
        return r;
    }, []);
    
console.log(uniques);
.as-console-wrapper { max-height: 100% !important; top: 0; }

#3


0  

You can create a map/object with name as key so that you will have unique items and override values if value is higher

您可以创建一个名称为键的地图/对象,这样您就可以拥有唯一的项目,如果值更高,则覆盖值

var groceryList = [
  {
    item: "Bananas",
    count: 4
  },
  {
    item: "Bananas",
    count: 3
  },
  {
    item: "Brussel Sprouts",
    count: 2
  },
  {
    item: "Bacon",
    count: 100
  },
  {
    item: "Beans",
    count: 19
  },
  {
    item: "Beans",
    count: 5
  }
];

let result = groceryList.reduce((map, obj) => {
   if (!(obj.item in map) || (obj.item in map && map[obj.item] < obj.count)) {
      map[obj.item] = obj.count;
   }
   return map;
}, {});
result = Object.keys(result).map(item => ({item , count: result[item]}));
console.log(result);

#4


0  

Here's another answer, a little simpler perhaps. Basically using the fact that an object has unique keys and Math.max to pick the larger number of items.

这是另一个答案,也许更简单一些。基本上使用一个对象具有唯一键和Math.max来挑选更多项目的事实。

newList = [];
for(var i in groceryList){
  let count = newList[groceryList[i].item] || 0;
    newList[groceryList[i].item] = Math.max(groceryList[i].count, count);
};

console.log(newList);

Fiddle: https://jsfiddle.net/w2szmmya/

#1


2  

You can use reduce to concisely transform an array into another (or into an object) when the input items and output items aren't necessarily one-to-one:

当输入项和输出项不一定是一对一时,您可以使用reduce将数组简洁地转换为另一个(或转换为对象):

var groceryList=[{item:"Bananas",count:4},{item:"Bananas",count:3},{item:"Brussel Sprouts",count:2},{item:"Bacon",count:100},{item:"Beans",count:19},{item:"Beans",count:5}]
const filteredListObj = groceryList.reduce((a, { item, count }) => {
  // this is a new item, or a duplicate with a greater quantity:
  if (!a[item] || a[item].count < count) a[item] = { item, count };
  return a;
}, {});
const filteredList = Object.values(filteredListObj);
console.log(filteredList);

#2


1  

You could take a hash table and use the original objects without creating new ones.

您可以使用哈希表并使用原始对象而无需创建新对象。

var groceryList = [ { item: "Bananas", count: 3 }, { item: "Bananas", count: 4 }, { item: "Brussel Sprouts", count: 2 }, { item: "Bacon", count: 100 }, { item: "Beans", count: 19 }, { item: "Beans", count: 5 }],
    hash = Object.create(null),
    uniques = groceryList.reduce((r, o) => {
        if (!(o.item in hash)) {
            hash[o.item] = r.push(o) - 1;
        }
        if (r[hash[o.item]].count < o.count) {
            r[hash[o.item]] = o;
        }
        return r;
    }, []);
    
console.log(uniques);
.as-console-wrapper { max-height: 100% !important; top: 0; }

#3


0  

You can create a map/object with name as key so that you will have unique items and override values if value is higher

您可以创建一个名称为键的地图/对象,这样您就可以拥有唯一的项目,如果值更高,则覆盖值

var groceryList = [
  {
    item: "Bananas",
    count: 4
  },
  {
    item: "Bananas",
    count: 3
  },
  {
    item: "Brussel Sprouts",
    count: 2
  },
  {
    item: "Bacon",
    count: 100
  },
  {
    item: "Beans",
    count: 19
  },
  {
    item: "Beans",
    count: 5
  }
];

let result = groceryList.reduce((map, obj) => {
   if (!(obj.item in map) || (obj.item in map && map[obj.item] < obj.count)) {
      map[obj.item] = obj.count;
   }
   return map;
}, {});
result = Object.keys(result).map(item => ({item , count: result[item]}));
console.log(result);

#4


0  

Here's another answer, a little simpler perhaps. Basically using the fact that an object has unique keys and Math.max to pick the larger number of items.

这是另一个答案,也许更简单一些。基本上使用一个对象具有唯一键和Math.max来挑选更多项目的事实。

newList = [];
for(var i in groceryList){
  let count = newList[groceryList[i].item] || 0;
    newList[groceryList[i].item] = Math.max(groceryList[i].count, count);
};

console.log(newList);

Fiddle: https://jsfiddle.net/w2szmmya/