使用下划线或lodash或vanilla js,如何找出最常出现的数组元素?

时间:2016-06-14 23:12:39

标签: javascript arrays underscore.js lodash

如果我有一个包含对象的数组,我该如何找出该数组中最常出现的对象?

让我们说数组是一个包含产品的数组,每个产品都是一个具有唯一ID的对象(每个产品唯一的不是数组中的每个元素):

const products = [
  {
    "itemId": "573412ab18c933d0085ca8b2",
    "price": 20,
    "cartQuantity": 1,
    "itemName": "Tea"
  },
  {
    "itemId": "573c82bd5c5ade1100532ec0",
    "price": 100,
    "cartQuantity": 1,
    "itemName": "Carpet"
  },
  {
    "itemId": "5734126218c933d0085ca8b0",
    "_id": "57608d4187faf12708605360",
    "price": 15,
    "cartQuantity": 1,
    "itemName": "Black Coffee"
  },
  {
    "itemId": "573412dd18c933d0085ca8b3",
    "_id": "57608d3d87faf12708605362",
    "price": 50,
    "cartQuantity": 1,
    "itemName": "Nyquil"
  },
  {
    "itemId": "573412ab18c933d0085ca8b2",
    "price": 20,
    "cartQuantity": 1,
    "itemName": "Tea"
  }
];

在上面的代码片段中,您可以看到" Tea"最常发生。我目前缺乏必要的算法知识,无法弄清楚如何吸取"茶"该数组中的对象是最常出现的元素。此外,如果有人可以在这里帮助我,重要的是要记住一个异常情况,即阵列中的两个元素出现的次数相同,并且它们会相互关联。因为最常见。

如果这对于某人来说是一个容易解决的问题,请轻松解释我并详细解释,因为您的耐心允许您如何解决这个问题,因为我还在学习。随意用下划线或lodash函数回答!

4 个答案:

答案 0 :(得分:0)

我认为最简单的方法是遍历数组并将当前产品的每个itemId作为一个键添加到对象中(包含计数为1的值,以及数组中的索引)。

如果元素已经在对象中,则将计数值递增1.最后,您只需找到对象中的最大计数值。

解决方案:

function mostOccuringProduct(productList) {
  const frequencies = {};

  // iterating through each product counting the occurrence of each itemId
  productList.forEach((product, i) => {
    if (product.itemId in frequencies) {
      frequencies[product.itemId].count++;
    } else {
      frequencies[product.itemId] = { count: 1, index: i };
    }
  })

  // find max number of occurences of any 1 item
  const maxOccurences = _.max(frequencies, item => item.count);
  // get array of items that tie for this maxOccurences #
  const itemsMatchingMaxOccurences = _.filter(frequencies, item => item.count === maxOccurences.count);
  // create array of just the indicies of the items that tie for the maxNumber of occurences
  const indicesOfMaxOccuringItems = _.map(itemsMatchingMaxOccurences, frequency => frequency.index);

  // initialize an array to hold all items that tie for max occurencies
  const products = [];
  // push items to this array
  indicesOfMaxOccuringItems.forEach(index => products.push(productList[index]));


  // return an array of all products that occur most frequently.
  // or just return the product that occurs most IF there is only one.
  return products.length > 1 ? products : products[0];
}

此解决方案将返回一系列产品,这些产品与列表中出现次数最多的产品相关联。如果只有一个项目,它将返回1个项目。

答案 1 :(得分:0)

您可以将输出格式化为:

[
  {
    "itemId": "573412ab18c933d0085ca8b2",
    "ocurrences": 2
  },
  {
    "itemId": "573c82bd5c5ade1100532ec0",
    "ocurrences": 1
  },
  ...
  ]

什么是排序数组,其中第一个元素是数组中重复次数最多的元素。按照排序,您可以轻松检查第二个或下一个元素是否具有相同的发生次数。

要实现这一目标,你需要这样的东西:

let getOcurrences = array =>{
  let ocurrences = {};
  array.forEach(item=>{
    if (!ocurrences[item.itemId])
      ocurrences[item.itemId] = 1;
    else 
      ocurrences[item.itemId] += 1;
  });
  return Object.keys(ocurrences)
    .map(itemId => ({
      itemId : itemId,
      ocurrences : ocurrences[itemId]
    }))
    .sort((a, b)=> b.ocurrences - a.ocurrences);
};

const products = [
  {
    "itemId": "573412ab18c933d0085ca8b2",
    "price": 20,
    "cartQuantity": 1,
    "itemName": "Tea"
  },
  {
    "itemId": "573c82bd5c5ade1100532ec0",
    "price": 100,
    "cartQuantity": 1,
    "itemName": "Carpet"
  },
  {
    "itemId": "5734126218c933d0085ca8b0",
    "_id": "57608d4187faf12708605360",
    "price": 15,
    "cartQuantity": 1,
    "itemName": "Black Coffee"
  },
  {
    "itemId": "573412dd18c933d0085ca8b3",
    "_id": "57608d3d87faf12708605362",
    "price": 50,
    "cartQuantity": 1,
    "itemName": "Nyquil"
  },
  {
    "itemId": "573412ab18c933d0085ca8b2",
    "price": 20,
    "cartQuantity": 1,
    "itemName": "Tea"
  }
];
console.log(getOcurrences(products));

答案 2 :(得分:0)

我建议使用hashmap来计算出现的次数,同时迭代产品&跟踪最常见的产品:

function getMostFrequent(array, identityFn) {
  var counts = {}, max = 0, result;
  
  array.forEach(element => {
    var id = (identityFn && identityFn(element)) || element,
        count = counts[id] = (counts[id] || 0) + 1;
    if (count > max) {
      max = count;
      result = element;
    }
  });
  return result;
}

const products = [{"itemId": 1}, {"itemId": 2}, {"itemId": 2}, {"itemId": 3}];

var mostFrequent = getMostFrequent(products, p => p["itemId"]);

console.log(mostFrequent);

如果您希望所有产品与最常用的产品相关联,而不仅仅是第一个产品,请将结果声明为Array并在count == max上推送元素。

getMostFrequent()的说明:

我们遍历给定array中的所有元素以及每个元素...

  • 通过提供的id回调函数获取identityFn
  • id
  • 初始化或增加此counts[id] = (counts[id] || 0) + 1;的计数器
  • 并最终与目前最常见的元素进行比较,如果更频繁地更新,则更新。

答案 3 :(得分:0)

这是我的 O(n)解决方案。我们创建一个哈希表,并将哈希表中的计数保存在一个名为indices的单独属性中,这是一个数组。当项目首次出现时,它的索引值(在products数组中)将被插入到索引数组索引位置1.当另一个项目首次出现时,它将覆盖索引位置1。因此,当项目第二次出现时,它会在索引[2]处插入,依此类推。最后,indices.pop()将为我们提供最频繁的产品项目索引,而且我们不会改变产品数组。



var products = [
  {
    "itemId": "573412ab18c933d0085ca8b2",
    "price": 20,
    "cartQuantity": 1,
    "itemName": "Tea"
  },
  {
    "itemId": "573c82bd5c5ade1100532ec0",
    "price": 100,
    "cartQuantity": 1,
    "itemName": "Carpet"
  },
  {
    "itemId": "5734126218c933d0085ca8b0",
    "_id": "57608d4187faf12708605360",
    "price": 15,
    "cartQuantity": 1,
    "itemName": "Black Coffee"
  },
  {
    "itemId": "573412dd18c933d0085ca8b3",
    "_id": "57608d3d87faf12708605362",
    "price": 50,
    "cartQuantity": 1,
    "itemName": "Nyquil"
  },
  {
    "itemId": "573412ab18c933d0085ca8b2",
    "price": 20,
    "cartQuantity": 1,
    "itemName": "Tea"
  }
],
lut = products.reduce((p,c,i) => { ++p[c.itemId] || (p[c.itemId] = 1);
                                   p.indices[p[c.itemId]] = i;
                                   return p;
                                 },{indices:[]});
console.log(lut);
console.log(products[lut.indices[lut.indices.length-1]]);