2

let's say that I have an array of objects that is structured like below:

let fruits = [
 {type: 'apple', count:1},
 {type: 'apple', count:2},
 {type: 'apple', count:3},
 {type: 'orange', count:2},
 {type: 'orange', count:3},
 {type: 'orange', count:4},
 {type: 'banana', count:3},
 {type: 'banana', count:4}
]

I am trying to sort the array first by 'type', and then by 'count'. However, I want to do it in batches. That is, the sorted array would first show the smallest count entries per each type of fruit, whose orders are sorted by 'type', and then second smallest count entries, etc...The result should be like below:

let fruits = [
 {type: 'apple', count:1},
 {type: 'banana', count:3},
 {type: 'orange', count:2},
 {type: 'apple', count:2},
 {type: 'banana', count:4},
 {type: 'orange', count:3},
 {type: 'apple', count:3},
 {type: 'orange', count:4}
]

One way I can think about is to create new arrays from the original array to include the lowest counts, second lowest counts, etc... and then use the arrays to create a new array in the intended order, but looks like this will be a complicated code and wondered what would be the better way to do this.

Any suggestions/ideas? Thanks a lot in advance!

3
  • Do you have any example of what you have tried so far here? Commented May 4, 2020 at 8:21
  • I don't think there's a way around that - "grouping them in several arrays, sorting them individually, merging them together" is probably actually the easiest to understand and program. No, you cannot do this in a single sort(), the comparison criterion is not consistent. Commented May 4, 2020 at 8:21
  • It's not trivial to do. Commented May 4, 2020 at 8:27

1 Answer 1

3

You could sort the array in advance by

  • type ascending,
  • count ascending

and then take an object for the order of same type as group and get an array of index, group and object.

After sorting, map the object as result.

let fruits = [{ type: 'apple', count: 1 }, { type: 'apple', count: 2 }, { type: 'apple', count: 3 }, { type: 'orange', count: 2 }, { type: 'orange', count: 3 }, { type: 'orange', count: 4 }, { type: 'banana', count: 3 }, { type: 'banana', count: 4 }],
    groups = Object.create(null),
    result = fruits
        .sort((a, b) => a.type.localeCompare(b.type) || a.count - b.count)
        .map((object, index) => ({ index, group: groups[object.type] = (groups[object.type] || 0) + 1, object }))
        .sort((a, b) => a.group - b.group || a.index - b.index)
        .map(({ object }) => object);

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

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

3 Comments

I'd rename .group to .indexInGroup or .indexPerType. And instead of comparing by overall index, you could just compare by type again.
index is only used for unstable sorting algos.
Hello, this is really cool solution. You made my day. Thanks a lot!!

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.