简体   繁体   English

如何根据数组字段中元素的出现次数对两个对象进行“排序”?

[英]How to 'sort' two objects based on number of occurrences of elements in an array field?

If I have two objects, and they both have two array fields within them, like so:如果我有两个对象,并且它们内部都有两个数组字段,如下所示:

const list1 = {
  name: 'list-1',
  fruits: ['banana', 'strawberry', 'cherry'],
  vegs: ['lettuce', 'avocado', 'beans']
};

const list2 = {
  name: 'list-2',
  fruits: ['banana', 'apple', 'orange', 'watermelon'],
  vegs: ['potato', 'avocado', 'onion', 'cabbage']
};

And then, I pass in two arrays, one of fruits, and one of vegetables, eg:然后,我传入两个数组,一个是水果,一个是蔬菜,例如:

const fruits = ['banana', 'strawberry'];
const vegetables = ['potato', 'lettuce', 'avocado'];

How can I order the objects, so that has the one with most number of fruits and vegetables (based on the passed in arrays) is on top?我如何订购这些对象,以便让水果和蔬菜数量最多的对象(基于传入的数组)位于顶部?

In this case that'd be list1 , since it has both "banana" and "strawberry" in fruits, and also has "lettuce" and "avocado" in vegs (ie 4 matches in total), whereas list2 only has 2 hits in total.在这种情况下是list1 ,因为它在水果中既有“香蕉”和“草莓”,在蔬菜中也有“生菜”和“鳄梨”(即总共 4 个匹配项),而list2在全部的。

Not sure if that makes a lot of sense, but what would be the most efficient way to order the two objects based on the arrays?不确定这是否有意义,但是根据数组对两个对象进行排序的最有效方法是什么?

If I'm understanding your question correctly, first you need to put your objects into their own array and then you can use Array.Prototype.sort: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort如果我正确理解您的问题,首先您需要将对象放入自己的数组中,然后您可以使用 Array.Prototype.sort: https ://developer.mozilla.org/en-US/docs/Web/JavaScript /参考/Global_Objects/数组/排序

Eg.例如。

const list1 = {
  name: 'list-1',
  fruits: ['banana', 'strawberry', 'cherry'],
  vegs: ['lettuce', 'avocado', 'beans']
};

const list2 = {
  name: 'list-2',
  fruits: ['banana', 'apple', 'orange', 'watermelon'],
  vegs: ['potato', 'avocado', 'onion', 'cabbage']
};

const arrayOfLists = [list1, list2]

arrayOfLists.sort((a, b) => (a.fruits.length + a.vegs.length) < (b.fruits.length + b.vegs.length) )

console.log(arrayOfLists) // Output = [list2, list1] because list 2 has more fruits and vegetables

First, you'll need to define an intersection function - a function that, given two lists, returns a new list containing only the elements found in both lists.首先,您需要定义一个intersection函数——一个给定两个列表的函数,它返回一个仅包含两个列表中的元素的新列表。 There's a very comprehensive answer here if you want to write your own version, or plenty of libraries that you can use to accomplish this (eg Ramda or Lodash ).如果您想编写自己的版本,或者您可以使用大量库来完成此操作(例如RamdaLodash ), 这里有一个非常全面的答案。 You could do this within your sort function, but it's not hard to imagine that you'd need it again in other contexts so it probably makes sense to have a reusable function.您可以在排序函数中执行此操作,但不难想象在其他上下文中您会再次需要它,因此拥有可重用函数可能是有意义的。

Assuming you've got an implementation of this function available, you can now write a custom compare function that can be used to order objects shaped like list1 and list2 according to the rules you've provided, something like this:假设您已经实现了此函数,您现在可以编写一个自定义比较函数,该函数可用于根据您提供的规则对形状为list1list2的对象进行排序,如下所示:

const compareByTotal = (a, b) => {
    const aTotal = intersection(a.fruits, fruits).length + intersection(a.vegs, vegetables).length;
    const bTotal = intersection(b.fruits, fruits).length + intersection(b.vegs, vegetables).length;
 
    return bTotal - aTotal;
}

Finally, you can use this function as a parameter when calling sort to produce a sorted list of these objects:最后,您可以在调用sort时将此函数用作参数以生成这些对象的排序列表:

[list1, list2].sort(compareByTotal);

I think it's fairly easy by looping through them and giving a score to each one then just select a winner that would go like我认为通过循环遍历它们并给每个分数打分然后选择一个获胜者是相当容易的

 const list1 = { name: 'list-1', fruits: ['banana', 'strawberry', 'cherry'], vegs: ['lettuce', 'avocado', 'beans'] }; const list2 = { name: 'list-2', fruits: ['banana', 'apple', 'orange', 'watermelon'], vegs: ['potato', 'avocado', 'onion', 'cabbage'] }; const fruits = ['banana', 'strawberry']; const vegetables = ['potato', 'lettuce', 'avocado']; const selectAWinner = (fruits,vegetables)=>{ let list1Score = 0; let list2Score = 0; fruits.forEach(fruit=>{ list1.fruits.forEach(fruitFromTheList=>{ if (fruitFromTheList === fruit) list1Score++ }) }) vegetables.forEach(vegetable=>{ list1.vegs.forEach(vegetableFromTheList=>{ if (vegetableFromTheList === vegetable) list1Score++ }) }) fruits.forEach(fruit=>{ list2.fruits.forEach(fruitFromTheList=>{ if (fruitFromTheList === fruit) list2Score++ }) }) vegetables.forEach(vegetable=>{ list2.vegs.forEach(vegetableFromTheList=>{ if (vegetableFromTheList === vegetable) list2Score++ }) }) if (list1Score > list2Score) document.write("list 1 wins with score " + list1Score) else if (list1Score < list2Score) document.write("list 2 wins with score " + list2Score) else document.write("it's a tie") // or do something else with the results } selectAWinner(fruits,vegetables)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM