0

I have this object of student grade data, looks something like this

data = {
 9: {
  Math: {
   className: {
     grade: 'A'
   }
   className2: {
     grade: 'A'
   }
  }
  History: {
   className: {
     grade: 'A'
   }
   className2: {
     grade: 'A'
   }
  }
  English: {
   className: {
     grade: 'A'
   }
   className2: {
     grade: 'A'
   }
  }
 }
}

it goes from 9-12.

I was wondering if I could sort the Math/History/English part in a specific order, like I want English first then Math then History.

Thanks

reid poynter
  • 41
  • 1
  • 6
  • 1
    No, you can't. Objects are not ordered. Use an array instead if you care. – Bergi Oct 21 '20 at 23:32
  • Basically, take the advice in [Sorting object property by values](https://stackoverflow.com/q/1069666/215552) and apply it to your object, then create an array of the names you want in order, and use the answers to [Javascript - sort array based on another array](https://stackoverflow.com/q/13304543/215552) to sort them. – Heretic Monkey Oct 21 '20 at 23:37

2 Answers2

0

Your data structure doesn't look the most suitable for what you want to achieve, but yes - you can order the object if you want to. Starting from ES2015, the order of object keys is granted, so having these school subjects in desired order makes some sense.

Try Array.prototype.reduce to achieve the desired order:

const subjects = ['English', 'Math', 'History'];

const orderedData = Object.entries(data).reduce((result, [n, nData]) => ({
    ...result,
    [n]: subjects.reduce((entry, subject) => ({
        ...entry,
        [subject]: nData[subject]
    }), {})
}), {});

// orderedData now contains new object in desired order
Robo Robok
  • 21,132
  • 17
  • 68
  • 126
0

As Bergi already did point to, one has to restructure each class level's value from what is now an object structure into an array of subject (related) data ...

const sampleData = {
  9: {
    Math: {
      className: { grade: 'A' },
      className2: { grade: 'A' }
    },
    History: {
      className: { grade: 'A' },
      className2: { grade: 'A' }
    },
    English: {
      className: { grade: 'A' },
      className2: { grade: 'A' }
    }
  },
  10: {
    Math: { className: { grade: 'A' } },
    History: { className: { grade: 'A' } },
    English: { className: { grade: 'A' } }
  }
};
const subjectPrecedence = new Map(
  ['English', 'Math', 'History'].map((subject, idx) => [subject, idx])
);  

function compareEntryKeysViaBoundPrecedenceMap(entryA, entryB) {
  return (this.get(entryA[0]) - this.get(entryB[0]));
}

function restructureClassEntry(collector, classEntry) {
  const { data, compareSubjectEntries } = collector;
  const [ classLevel, levelData ] = classEntry;

  data[classLevel] = Object
    .entries(levelData)
    .sort(compareSubjectEntries)
    .map(entry => Object.fromEntries([entry]));

  return collector;
}

const orderedClassData = Object
  .entries(sampleData)
  .reduce(restructureClassEntry, {

    compareSubjectEntries: compareEntryKeysViaBoundPrecedenceMap.bind(subjectPrecedence),
    data: {}

  }).data;

console.log('[...subjectPrecedence.entries()] :', [...subjectPrecedence.entries()]);
console.log('orderedClassData :', orderedClassData);
.as-console-wrapper { min-height: 100%!important; top: 0; }
Peter Seliger
  • 11,747
  • 3
  • 28
  • 37