简体   繁体   中英

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.

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

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. 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 ). 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:

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:

[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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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