计算数组中匹配对象数量的有效方法

问题描述 投票:0回答:6

请参阅下面的尝试和示例,我正在寻找一种在 JS 中有效的方法来获取匹配的水果数量。目前我正在使用过滤器在

items
数组中查找匹配项,但我想知道是否有更好的方法 (无需在每次迭代时过滤
fruits
数组 ~ 想象它是一个更大的水果数组)
.

  const items = [
    {
      id: '111',
      name: 'apple',
    },
    {
      id: '222',
      name: 'apple',
    },
    {
      id: '333',
      name: 'kiwi',
    },
  ];

  const fruits = [
    {
      id: 'fruit-1',
      name: 'apple',
    },
    {
      id: 'fruit-2',
      name: 'banana',
    },
    {
      id: 'fruit-3',
      name: 'kiwi',
    },
  ];

  // attempted
  const numberOfFruitsInItems = fruits.map((fruit) => {
    const itemsWithFruit = items.filter(({ name }) => fruit.name === name);

    return {
      ...fruit,
      total: itemsWithFruit.length,
    };
  });

  console.log(numberOfFruitsInItems);

  // desired response
  [
    {
      id: 'fruit-1',
      name: 'apple',
      total: 2,
    },
    {
      id: 'fruit-2',
      name: 'banana',
      total: 0,
    },
    {
      id: 'fruit-3',
      name: 'kiwi',
      total: 1,
    },
  ];
javascript algorithm
6个回答
0
投票

您可以通过 items

one
迭代来完成此任务,从而更新相应水果的全局计数器。

// Use a hashed object to keep count of totals per fruit name.
// totals[FRUIT NAME] = ...number of items having name=FRUIT NAME
const totals = {}

// Fill the totals hash in one single iteration of items
items.forEach(item => {
  totals[item.name] = (totals[item.name] || 0) + 1
})

const numberOfFruitsInItems = fruits.map((fruit) => {
  return {
    ...fruit,
    total: totals[fruit.name] || 0,
  };
});


0
投票

正如本网站上的许多问题和答案一样,您应该按

name
对对象数组进行分组,对每个对象进行计数并将其存储在
grouped
对象中,其键是名称和计数值。

const items = [{id:"111",name:"apple"},{id:"222",name:"apple"},{id:"333",name:"kiwi"},];
const fruits = [{id:"fruit-1",name:"apple"},{id:"fruit-2",name:"banana"},{id:"fruit-3",name:"kiwi"},];

var grouped = items.reduce(function(agg, item) {
  agg[item.name] = (agg[item.name] || 0) + 1
  return agg
}, {})

fruits.forEach(function(item) {
  item.total = grouped[item.name] || 0
})

console.log(fruits)
.as-console-wrapper {max-height: 100% !important}


0
投票

您需要在映射每个水果之前缓存项目频率。

const
  items = [
    { id: '111', name: 'apple' },
    { id: '222', name: 'apple' },
    { id: '333', name: 'kiwi' }
  ],
  fruits = [
    { id: 'fruit-1', name: 'apple' },
    { id: 'fruit-2', name: 'banana' },
    { id: 'fruit-3', name: 'kiwi' }
  ];

const main = () => {
  const reducedFruits = fruitReducer(fruits, items);
  console.log(reducedFruits);
};

const computeFrequency = (items, accessor) =>
  items.reduce((acc, item) =>
    (key =>
      acc.set(key, (acc.get(key) ?? 0) + 1))
    (accessor ? accessor(item) : item), new Map);

const fruitReducer = (fruits, items) =>
  ((freqMap) =>
    fruits.map(({ id, name }) =>
      ({ id, name, total: freqMap.get(name) ?? 0 })))
  (computeFrequency(items, ({ name }) => name))

main();
.as-console-wrapper { top: 0; max-height: 100% !important; }


0
投票

最好将两种机制分开以消除嵌套迭代。首先使用

items
 迭代 
reduce
数组以创建键/值对的字典(例如
{ apple: 2 }
,然后 then 循环遍历
fruits
数组,添加字典中的正确计数信息。

const items=[{id:"111",name:"apple"},{id:"222",name:"apple"},{id:"333",name:"kiwi"}],fruits=[{id:"fruit-1",name:"apple"},{id:"fruit-2",name:"banana"},{id:"fruit-3",name:"kiwi"}];

// `reduce` over the items.
// If the item name isn't a key on the object
// set it to zero, then add one
const itemCount = items.reduce((acc, { name }) => {
  fruits[name] ??= 0;
  ++fruits[name];
  return fruits;
}, {});

// Update the `fruits` using the dictionary
// count information - note this mutates the
// `fruits` array so if you want a new array
// use `map` instead of `forEach`
fruits.forEach(fruit => {
  fruit.count = itemCount[fruit.name] || 0;
});

console.log(fruits);

附加信息


0
投票

一个不会改变你的原始数据的版本——毕竟我们不是野蛮人,对吧? -- 可以首先创建

fruit
数组的副本,为每个副本添加
count
属性,将它们存储为与水果名称无关的对象,然后通过增加
items
属性将
count
列表折叠到其中的相关节点。最后,我们只是收集并返回该对象的
values

代码非常简单:

const countFruits = (fruits, items) => Object .values (items .reduce (
  (a, {name}) => ((a [name] .count += 1), a),
  fruits .reduce ((a, f) => ((a [f .name] = {...f , count: 0}), a), {})
))

const items = [{id: '111', name: 'apple'}, {id: '222', name: 'apple'}, {id: '333', name: 'kiwi'}]
const fruits = [{id: 'fruit-1', name: 'apple', }, {id: 'fruit-2', name: 'banana', }, {id: 'fruit-3', name: 'kiwi', }]

console .log (countFruits (fruits, items))
.as-console-wrapper {max-height: 100% !important; top: 0}

请注意,没有错误检查,但您可能需要它。如果

items
包含
{id" 444', name: 'papaya'}
,即使
paypaya
不在水果列表中怎么办?这应该不会太难处理,我们可以把它作为练习。


0
投票
  const fruits = [
    { Apple: 4, Orange: 7, Grape: 3 },
    { Guava: 6, Lemon: 4, Banana: 8 },
    { Orange: 5, Pineapple: 7, Apple: 7 },
  ];

  let fruitCount = {};

  fruits.forEach((item) => {
    for (let fruit in item) {
      if (fruitCount[fruit]) {
        fruitCount[fruit] = fruitCount[fruit] + item[fruit];
      } else {
        fruitCount[fruit] = item[fruit];
      }
    }
  });

  console.log(fruitCount);
© www.soinside.com 2019 - 2024. All rights reserved.