Home > Software engineering >  sort a complex structure array of objects
sort a complex structure array of objects

Time:11-15

I have such an array of card objects:

const cards = [
  {
    type: { method: 'listen' },
    reference: ['destroyed', 'word 2']
  },
  {
    type: { method: 'synonym' },
    reference: ['destroyed']
  },
  {
    type: { method: 'listen' },
    reference: ['destroyed']
  },
  {
    type: { method: 'dictate' },
    reference: ['destroyed']
  }
]

I want to sort them as follows:

  1. the listen cards should come first
  2. between listen cards the ones that have less reference.length should come earlier
  3. any other cards should come then
  4. dictate cards should come at last

I have no idea how to do such a complex sorting except doing the first condition:

    cards.sort(compare);

    function compare(a, b) {
        if(a.type.method == 'listen') return a.reference.length - b.reference.length;
        ...
    }

CodePudding user response:

Write out all the cases you want to do something "special" in:

const cards = [
  {
    type: { method: 'listen' },
    reference: ['destroyed', 'word 2']
  },
  {
    type: { method: 'synonym' },
    reference: ['destroyed']
  },
  {
    type: { method: 'listen' },
    reference: ['destroyed']
  },
  {
    type: { method: 'dictate' },
    reference: ['destroyed']
  }
];

cards.sort((a, b) => {
    // both types are 'dictate' - no change
    if (a.type.method === "dictate" && b.type.method === "dictate") return 0;
    // move `b` up since `a` is 'dictate'
    if (a.type.method === "dictate") return 1;
    // move `a` up since `b` is 'dictate'
    if (b.type.method === "dictate") return -1;
    
    // if both are 'listen' then order based on refs
    if (a.type.method === "listen" && b.type.method === "listen") return a.reference.length - b.reference.length;
    // move `a` up since `a` is 'listen'
    if (a.type.method === "listen") return -1;
    // move `b` up since `b` is 'listen'
    if (b.type.method === "listen") return 1;

    // no change
    return 0;
});

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

CodePudding user response:

const cards = [
  {
    type: { method: 'listen' },
    reference: ['destroyed', 'word 2']
  },
  {
    type: { method: 'synonym' },
    reference: ['destroyed']
  },
  {
    type: { method: 'listen' },
    reference: ['destroyed']
  },
  {
    type: { method: 'dictate' },
    reference: ['destroyed']
  }
]

const sortedCards = cards.sort((a, b) => {
  const priority = ['listen', 'synonym', 'dictate'];
  const indexA = priority.indexOf(a.type.method);
  const indexB = priority.indexOf(b.type.method);
  
  // First try to compare against the type
  // If the types are equal, it will be eval to 0 from (indexA - indexB).
  // 0 is considered false in javascript and hence will evulate the length of the reference.
  return indexA - indexB || a.reference.length - b.reference.length;
});

console.log(sortedCards);

CodePudding user response:

When the sort() function compares two values, it sends the values to the compare function, and sorts the values according to the returned (negative, zero, positive) value.

If the result is negative, a is sorted before b.

If the result is positive, b is sorted before a.

If the result is 0, no changes are done with the sort order of the two values.

Example:

The compare function compares all the values in the array, two values at a time (a, b).

When comparing 40 and 100, the sort() method calls the compare function(40, 100).

The function calculates 40 - 100 (a - b), and since the result is negative (-60), the sort function will sort 40 as a value lower than 100.

You can use this code snippet to experiment with numerically and alphabetically sorting:

So based on that (even though its kinda ugly):

cards.sort(compare);
function compare(a, b) {
          if(b.type.method == "dictate") return -1000
          if(a.type.method == "listen" && b.type.method !== "listen") return -1.5
          if(a.type.method === "listen" && b.type.method === "listen") 
      return a.reference.length - b.reference.length
    }
const cards = [
      {
        type: { method: 'listen' },
        reference: ['destroyed', 'word 2']
      },
      {
        type: { method: 'synonym' },
        reference: ['destroyed']
      },
      {
        type: { method: 'listen' },
        reference: ['destroyed']
      },
      {
        type: { method: 'dictate' },
        reference: ['destroyed 1']
      },
      {
        type: { method: 'listen' },
        reference: ['destroyed', 'word 2', 'type 3']
      },
      {
        type: { method: 'synonym' },
        reference: ['destroyed']
      },
      {
        type: { method: 'listen' },
        reference: ['destroyed', 'listen']
      },
      {
        type: { method: 'dictate' },
        reference: ['destroyed']
      },
      {
        type: { method: 'listen' },
        reference: ['destroyed', 'listen']
      },
    ]
  • Related