0

I need to sort an array of nested objects. I wrote the following code but for some reasons it places the first element always in the returning array even if it should not.

orderedArray = () => {
    let sortedArray = products
    if(this.state.interests.design && this.state.interests.code && this.state.interests.business)
        sortedArray.sort((a,b)=> (b.scores.quality-a.scores.quality))
    else if(this.state.interests.design && this.state.interests.code)
        sortedArray.sort((a,b) => (b.scores.quality*b.scores.relevancy.code*b.scores.relevancy.design/2)-(a.scores.quality*a.scores.relevancy.code*a.scores.relevancy.design/2))
    else if(this.state.interests.design && this.state.interests.business)
        sortedArray.sort((a,b) => (b.scores.quality*b.scores.relevancy.business*b.scores.relevancy.design/2)-(a.scores.quality*a.scores.relevancy.business*a.scores.relevancy.design/2))
    else if(this.state.interests.business && this.state.interests.code)
        sortedArray.sort((a,b) => (b.scores.quality*b.scores.relevancy.business*b.scores.relevancy.code/2)-(a.scores.quality*a.scores.relevancy.business*a.scores.relevancy.code/2))
    else if(this.state.interests.business)
        sortedArray.sort((a,b)=> (b.scores.quality*b.scores.relevancy.business-a.scores.quality*a.scores.relevancy.busines))
    else if(this.state.interests.code)
        sortedArray.sort((a,b)=> (b.scores.quality*b.scores.relevancy.code-a.scores.quality*a.scores.relevancy.code))
    else if(this.state.interests.design)
        sortedArray.sort((a,b)=> (b.scores.quality*b.scores.relevancy.design-a.scores.quality*a.scores.relevancy.design))
    console.log(JSON.stringify(sortedArray))
    return sortedArray
}

The idea is that if they selected design, business and code then the resulting array should be sorted by quality, otherwise my a mix of quality and the selected variables. Here is the data:

[
    {
        "name":"dasd",
        "scores": {
            "quality": 8,
            "relevancy": {
                "design": 3,
                "code": 9,
                "business": 5
            }
        },
        {...}
    }
    {...}
]

Whereas this.state is:

    this.state = {
        minutes: int,
        interests: {
                business: bool,
                code: bool,
                design: bool
        }
    }
ocram
  • 1,384
  • 6
  • 20
  • 36
  • 3
    please add the data as well in literal notation. – Nina Scholz May 25 '17 at 19:03
  • 2
    What do you mean by "*places the first element always in the returning array*"? `sort` doesn't place or remove anything. – Bergi May 25 '17 at 19:06
  • the `sortedArray` has the same first element than at the beginning of the operation – ocram May 25 '17 at 19:07
  • [how-to-sort-an-array-of-objects-by-multiple-fields](https://stackoverflow.com/questions/6913512/how-to-sort-an-array-of-objects-by-multiple-fields) ? Even if it was not a duplicate, I think it would help to take a look. – Hugues M. May 25 '17 at 19:08
  • @NinaScholz added – ocram May 25 '17 at 19:12

1 Answers1

1

Using a formula does not work to sort an array on multiple properties.

Given an array of "student" objects with structure like {name:'Alice', age:8, grades:{math:12, gym:14}}, the following does not work:

// This does not sort by math then gym, it sorts by the result of their products, which is meaningless
students.sort((a,b) => (a.grades.math*a.grades.gym - b.grades.math*b.grades.gym))

As you can see in this Q/A, it's difficult to implement in JS, but there are libraries to help make this much straightforward, like underscore or lodash.

With lodash you can do this:

// This sorts by math score, then gym score
_.sortBy(students, [s => s.grades.math, s => s.grades.gym])

Now applying to your problem, without giving a complete solution, here is a hint:

var data = [...];
var propertiesToSortBy = [ o => o.scores.quality ];
// Your rules below
if (...) {
    propertiesToSortBy = [ o => o.scores.quality, o => o.scores.relevancy.business ];
}
else if (...) {
    propertiesToSortBy = [ o => o.scores.relevancy.design, o => o.scores.relevancy.business ];
}
else ...
// Finally, sort
_.sortBy(data, propertiesToSortBy);
Hugues M.
  • 19,846
  • 6
  • 37
  • 65