1

I am trying to sort an array of key-value paired objects using the index of a second array of arrays.

Consider the following code:

const sheet = [['ES'], ['MES'], ['NQ'], ['MNQ']] // sort in this order
const quotes = [{root: 'MNQ'}, {root: 'MES'}, {root: 'ES'}, {root: 'NQ'}] // sort these objects

const sorted = quotes.sort((a, b) => {
  return sheet.indexOf(a.root) - sheet.indexOf(b.root)
})

console.log(sorted)

When you run the above code, sorted has retained the same order as the original quotes variable and it appears as if no sort has taken place!

I feel like I'm almost there and my code just needs a small tweak to make it work.

3
  • @CertainPerformance, can you please explain the reason for the edit, so I don't make the same mistake again? Commented Dec 21, 2019 at 0:59
  • See meta.stackexchange.com/q/2950 - it's not a big problem, but Stack Overflow is meant to be a reference site, not a discussion forum, so "thanks" etc is just noise (and we're supposed to remove them from posts when we see them) Commented Dec 21, 2019 at 1:01
  • Noted and will be less 'chatty' from now on Commented Dec 21, 2019 at 1:04

3 Answers 3

3

sheet is an array of arrays, so sheet.indexOf anything other than an array taken from sheet will return -1.

Transform sheet to an array of strings first:

const sheet = [['ES'], ['MES'], ['NQ'], ['MNQ']]
  .map(([str]) => str);
const quotes = [{root: 'MNQ'}, {root: 'MES'}, {root: 'ES'}, {root: 'NQ'}] // sort these objects

const sorted = quotes.sort((a, b) => {
  return sheet.indexOf(a.root) - sheet.indexOf(b.root)
})

console.log(sorted)

Or use .findIndex instead of indexOf:

const sheet = [['ES'], ['MES'], ['NQ'], ['MNQ']];
const quotes = [{root: 'MNQ'}, {root: 'MES'}, {root: 'ES'}, {root: 'NQ'}] // sort these objects

const sorted = quotes.sort((a, b) => {
  return sheet.findIndex(arr => arr[0] === a.root) - sheet.findIndex(arr => arr[0] === b.root)
})

console.log(sorted)

Or, for better computational complexity (O(n log n)), transform sheet into an object indexed by string, whose values are the indicies:

const sheet = [['ES'], ['MES'], ['NQ'], ['MNQ']];
const sheetObj = {};
for (const [i, [str]] of sheet.entries()) {
  sheetObj[str] = i;
}
const quotes = [{root: 'MNQ'}, {root: 'MES'}, {root: 'ES'}, {root: 'NQ'}] // sort these objects

const sorted = quotes.sort((a, b) => sheetObj[a.root] - sheetObj[b.root]);

console.log(sorted)

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

1 Comment

Bingo! Thank you very much @CertainPerformance. I will accept your answer as soon as the 15 minute timer is over
1

You cannot use indexOf since sheet is an array of arrays. Try using findIndex() and comparing the only array element:

const sheet = [['ES'], ['MES'], ['NQ'], ['MNQ']] // sort in this order
const quotes = [{root: 'MNQ'}, {root: 'MES'}, {root: 'ES'}, {root: 'NQ'}] // sort these objects

let sorted = quotes.sort((a, b) => {
  return sheet.findIndex(([x]) => x === a.root) - sheet.findIndex(([x]) => x === b.root);
})

console.log(sorted);

Comments

1

A slightly different approach (which should be more efficient than using .sort() for larger arrays) you could use if your quotes array has unique {root} objects would be to make a new Map from your quotes array and then .map() your sheet array the {root} objects like so:

const sheet = [['ES'], ['MES'], ['NQ'], ['MNQ']];
const quotes = [{root: 'MNQ'}, {root: 'MES'}, {root: 'ES'}, {root: 'NQ'}] // sort these objects

const lut = new Map(quotes.map(({root}) => [root, {root}]));
const sorted = sheet.map(([s]) => lut.get(s));
console.log(sorted)

If you're you can have duplicates, you can use .reduce() instead of a new Map, and then .flatMap():

const sheet = [['ES'], ['MES'], ['NQ'], ['MNQ']];
const quotes = [{root: 'MNQ'}, {root: 'MES'}, {root: 'ES'}, {root: 'NQ'}, {root: 'MES'}] // sort these objects

const lut = quotes.reduce((acc, {root}) => {
  acc[root] = [...(acc[root] || []), {root}];
  return acc;
}, {});

const sorted = sheet.flatMap(([s]) => lut[s]);
console.log(sorted)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.