0

Working on a web game as a hobby. I have an "inventory" which contains pets:

interface Pet {
  type: string;
  level: number;
  isFavorite: boolean;
}

allPetSlots = [
  {slotState: INVENTORY_STATE.EQUIPPED, pet: {...},
  {slotState: INVENTORY_STATE.OCCUPIED, pet: {...},
  {slotState: INVENTORY_STATE.OCCUPIED, pet: {...},
  {slotState: INVENTORY_STATE.EMPTY, pet: null,
  {slotState: INVENTORY_STATE.EMPTY, pet: null,
  {slotState: INVENTORY_STATE.EMPTY, pet: null,
  {...}
]

I currently have a sortAll method that sorts the inventory on these specific criterias:

  1. FAVORITED PETS SHOW UP FIRST
  2. GROUP BY PET TYPE
  3. SORT BY LEVEL desc
  4. ALL EMPTY SPOTS SHOW UP AFTER

This is what I have:

allPetsSlots
        .sort((a) => (a.state === 'occupied' || a.state === 'equipped' ? -1 : 1))
        .sort((a, b) => {
            if (a.pet?.type < b.pet?.type) return -1;
            if (a.pet?.type > b.pet?.type) return 1;
            return 0;
        })
        .sort((a, b) => {
            if (a.pet?.type === b.pet?.type && a.pet?.level > b.pet?.level) return -1;
            if (a.pet?.type === b.pet?.type && a.pet?.level < b.pet?.level) return 1;
            return 0;
        })
        .sort((a, b) => {
            if (a.pet?.isFavorite || b.pet?.isFavorite) return -1;
            return 1;
        })

While this SEEMS to work in chrome: enter image description here

I'm having some troubles with other browsers. I'm pretty sure my sort function is doing something weird and my brain is extra foggy today.

Would appreciate any help!

const currentPets = [
  { state: 'empty', pet: null},
  { state: 'empty', pet: null},
  { state: 'empty', pet: null},
  { state: 'empty', pet: null},
  { state: 'empty', pet: null},
  { state: 'occupied', pet: { type: 'quartz', level: 2, isFavorite: false}},
  { state: 'occupied', pet: { type: 'quartz', level: 3, isFavorite: false}},
  { state: 'equipped', pet: { type: 'quartz', level: 6, isFavorite: true}},
  { state: 'occupied', pet: { type: 'quartz', level: 2, isFavorite: false}},
  { state: 'occupied', pet: { type: 'obsidian', level: 2, isFavorite: false}},
  { state: 'occupied', pet: { type: 'obsidian', level: 5, isFavorite: false}},
  { state: 'occupied', pet: { type: 'obsidian', level: 6, isFavorite: true}},
  { state: 'empty', pet: null},
  { state: 'empty', pet: null},
  { state: 'occupied', pet: { type: 'agate', level: 1, isFavorite: false}},
  { state: 'occupied', pet: { type: 'agate', level: 2, isFavorite: false}},
  { state: 'occupied', pet: { type: 'agate', level: 4, isFavorite: true}},
]

const sortAll = () => {
  currentPets
    .sort((a) => (a.state === 'occupied' || a.state === 'equipped' ? -1 : 1))
        .sort((a, b) => {
            if (a.pet?.type < b.pet?.type) return -1;
            if (a.pet?.type > b.pet?.type) return 1;
            return 0;
        })
        .sort((a, b) => {
            if (a.pet?.type === b.pet?.type && a.pet?.level > b.pet?.level) return -1;
            if (a.pet?.type === b.pet?.type && a.pet?.level < b.pet?.level) return 1;
            return 0;
        })
        .sort((a, b) => {
            if (a.pet?.isFavorite || b.pet?.isFavorite) return -1;
            return 0;
        })
}

console.log('sorted', currentPets)

5
  • 1
    Only the last sort really works! You can't sort an array in multiple steps, all the logic needs to be in one callback. Commented May 29, 2022 at 19:39
  • Oh interesting... its so weird it works in chrome... Commented May 29, 2022 at 19:40
  • As you say: it happens to. Commented May 29, 2022 at 20:05
  • Of course you can sort in multiple steps, but you never take undefined into consideration, which will always return "false", even if comparing to a boolean. So if it's undefined compared to true, the code won't sort at all. Commented May 29, 2022 at 20:05
  • I figured the first sort would handle the undefined since it would sort the occupied/equipped slots to the front and the empty slots to the back. Thats why I include the optional chaining in the subsequent sorts Commented May 29, 2022 at 20:07

1 Answer 1

1

You need to take undefined into consideration. I think it's a waste of resources to sort an array multiple times, because of the numerous loops that the sortings will demand.

I changed just the isFavorite sort for you. If I were you, I would just continue with more code under the first checked property (isFavorite).

const currentPets = [
  { state: 'empty', pet: null},
  { state: 'empty', pet: null},
  { state: 'empty', pet: null},
  { state: 'empty', pet: null},
  { state: 'empty', pet: null},
  { state: 'occupied', pet: { type: 'quartz', level: 2, isFavorite: false}},
  { state: 'occupied', pet: { type: 'quartz', level: 3, isFavorite: false}},
  { state: 'equipped', pet: { type: 'quartz', level: 6, isFavorite: true}},
  { state: 'occupied', pet: { type: 'quartz', level: 2, isFavorite: false}},
  { state: 'occupied', pet: { type: 'obsidian', level: 2, isFavorite: false}},
  { state: 'occupied', pet: { type: 'obsidian', level: 5, isFavorite: false}},
  { state: 'occupied', pet: { type: 'obsidian', level: 6, isFavorite: true}},
  { state: 'empty', pet: null},
  { state: 'empty', pet: null},
  { state: 'occupied', pet: { type: 'agate', level: 1, isFavorite: false}},
  { state: 'occupied', pet: { type: 'agate', level: 2, isFavorite: false}},
  { state: 'occupied', pet: { type: 'agate', level: 4, isFavorite: true}},
]


const sortAll = () => {
  let tempA, tempB;

  return currentPets
    .sort((a, b) => {
        tempA = a.pet?.isFavorite
        tempB = b.pet?.isFavorite

        // you should refactor this if statement
        if (tempA !== tempB) {
          if (typeof tempA == 'undefined') { return 1  }
          if (typeof tempB == 'undefined') { return -1 }
          if (tempA < tempB)               { return 1  }
          if (tempA > tempB)               { return -1 }
        }

        // tempA = a.pet?.type
        // tempB = b.pet?.type
        //if (tempA !== tempB) {
          // ...
        //}

        return 0
    })
}

console.log('sorted', sortAll());

And how is how it should look like if you refactored the code:

const currentPets = [
  { state: 'empty', pet: null},
  { state: 'empty', pet: null},
  { state: 'empty', pet: null},
  { state: 'empty', pet: null},
  { state: 'empty', pet: null},
  { state: 'occupied', pet: { type: 'quartz', level: 2, isFavorite: false}},
  { state: 'occupied', pet: { type: 'quartz', level: 3, isFavorite: false}},
  { state: 'equipped', pet: { type: 'quartz', level: 6, isFavorite: true}},
  { state: 'occupied', pet: { type: 'quartz', level: 2, isFavorite: false}},
  { state: 'occupied', pet: { type: 'obsidian', level: 2, isFavorite: false}},
  { state: 'occupied', pet: { type: 'obsidian', level: 5, isFavorite: false}},
  { state: 'occupied', pet: { type: 'obsidian', level: 6, isFavorite: true}},
  { state: 'empty', pet: null},
  { state: 'empty', pet: null},
  { state: 'occupied', pet: { type: 'agate', level: 1, isFavorite: false}},
  { state: 'occupied', pet: { type: 'agate', level: 2, isFavorite: false}},
  { state: 'occupied', pet: { type: 'agate', level: 4, isFavorite: true}},
]


const sortAll = (arr) => {
  const UNSORTED = 0;
  let   result   = 0;

  return arr
    .sort((a, b) => {
        result = compareProperties(a.pet?.isFavorite, b.pet?.isFavorite)

        // if (result == UNSORTED) {
        //  result = compareProperties(a.pet?.type, b.pet?.type)
        // }
        
        // if (result == UNSORTED) {
        // ...

        return result
    })
}

const compareProperties = (tempA, tempB) => {
  if (tempA !== tempB) {
    if (typeof tempA == 'undefined') { return 1  }
    if (typeof tempB == 'undefined') { return -1 }
    if (tempA < tempB)               { return 1  }
    if (tempA > tempB)               { return -1 }
  }

  return 0
}

console.log('sorted', sortAll(currentPets));

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.