1

My array object as follow

 var data = [{"weight":0,"name":"New Arrivals"},{"weight":0,"name":"Weekly Promotions"},{"weight":0,"name":"Sale"},{"weight":0,"name":"Extended Size"},{"weight":0,"name":"Accessories and Shoes"},{"weight":0,"name":"Activewear"},{"weight":0,"name":"Disney Project"},{"weight":0,"name":"Dresses and Jumpsuits"},{"weight":0,"name":"Fleece"},{"weight":0,"name":"HEATTECH Collection"},{"weight":0,"name":"Ines de la Fressange"},{"weight":0,"name":"Intimates"},{"weight":0,"name":"Jeans"},{"weight":0,"name":"Loungewear"},{"weight":0,"name":"Outerwear and Blazers"},{"weight":0,"name":"Pants"},{"weight":0,"name":"Shirts and Blouses"},{"weight":0,"name":"Skirts"},{"weight":0,"name":"Socks and Hosiery"},{"weight":0,"name":"Sweaters"},{"weight":0,"name":"Sweatshirts and Sweatpants"},{"weight":0,"name":"T-Shirts and Tops"},{"weight":0,"name":"UT: Graphic Tees"},{"weight":0,"name":"Wear To Work"},{"weight":0,"name":"Mix and Match"}]

Am trying to sort this based on the property weight, But in case if all the values of weight is 0, I need the original order as it is on the output. But this feature is not working as expected instead the order is changing.

Have used ramda as well as JavaScript sort

var sortedData = R.sortBy(R.prop('weight'), data);

or

var sortData = data.slice(0);
sortData.sort(function(a,b) {
    return a.weight - b.weight;
});

Both the case am getting result as below

var output = [{"weight":0,"name":"Jeans"},{"weight":0,"name":"New Arrivals"},{"weight":0,"name":"Sale"},{"weight":0,"name":"Extended Size"},{"weight":0,"name":"Accessories and Shoes"},{"weight":0,"name":"Activewear"},{"weight":0,"name":"Disney Project"},{"weight":0,"name":"Dresses and Jumpsuits"},{"weight":0,"name":"Fleece"},{"weight":0,"name":"HEATTECH Collection"},{"weight":0,"name":"Ines de la Fressange"},{"weight":0,"name":"Intimates"},{"weight":0,"name":"Weekly Promotions"},{"weight":0,"name":"Loungewear"},{"weight":0,"name":"Outerwear and Blazers"},{"weight":0,"name":"Pants"},{"weight":0,"name":"Shirts and Blouses"},{"weight":0,"name":"Skirts"},{"weight":0,"name":"Socks and Hosiery"},{"weight":0,"name":"Sweaters"},{"weight":0,"name":"Sweatshirts and Sweatpants"},{"weight":0,"name":"T-Shirts and Tops"},{"weight":0,"name":"UT: Graphic Tees"},{"weight":0,"name":"Wear To Work"},{"weight":0,"name":"Mix and Match"}]

Expected: when weight value is 0 for all the case, then am expecting the result as same as the input.

Any help appreciated.

nosdalg
  • 571
  • 1
  • 5
  • 23

5 Answers5

3

Your problem is that sorting in JavaScript is not guaranteed to be stable.The ECMA-262 spec states this with:

The elements of this array are sorted. The sort is not necessarily stable (that is, elements that compare equal do not necessarily remain in their original order).

The question Fast stable sorting algorithm implementation in javascript includes a link to this Vjeux blog post that speaks to stable sorting as well as several other options.

Community
  • 1
  • 1
DocMax
  • 12,094
  • 7
  • 44
  • 44
2

A suggestion with Sorting with map. Here you have the index and preserve the original sorting with the second chained sort criteria.

mapped.sort(function (a, b) {
    return a.value - b.value || a.index - b.index;
});

// the array to be sorted
var data = [{ weight: 0, name: "New Arrivals" }, { weight: 0, name: "Weekly Promotions" }, { weight: 0, name: "Sale" }, { weight: 0, name: "Extended Size" }, { weight: 0, name: "Accessories and Shoes" }, { weight: 0, name: "Activewear" }, { weight: 0, name: "Disney Project" }, { weight: 0, name: "Dresses and Jumpsuits" }, { weight: 0, name: "Fleece" }, { weight: 0, name: "HEATTECH Collection" }, { weight: 0, name: "Ines de la Fressange" }, { weight: 0, name: "Intimates" }, { weight: 0, name: "Jeans" }, { weight: 0, name: "Loungewear" }, { weight: 0, name: "Outerwear and Blazers" }, { weight: 0, name: "Pants" }, { weight: 0, name: "Shirts and Blouses" }, { weight: 0, name: "Skirts" }, { weight: 0, name: "Socks and Hosiery" }, { weight: 0, name: "Sweaters" }, { weight: 0, name: "Sweatshirts and Sweatpants" }, { weight: 0, name: "T-Shirts and Tops" }, { weight: 0, name: "UT: Graphic Tees" }, { weight: 0, name: "Wear To Work" }, { weight: 0, name: "Mix and Match" }];

// temporary array holds objects with position and sort-value
var mapped = data.map(function (el, i) {
        return {
            index: i, 
            value: el.weight
        };
    });

// sorting the mapped array containing the reduced values
mapped.sort(function (a, b) {
    return a.value - b.value || a.index - b.index;
});

// container for the resulting order
var result = mapped.map(function (el) {
    return data[el.index];
});

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
1

the simplest solution is to save position and then compare it if objects are equal:

var sortData = data.slice(0);

sortData.forEach(function(element, index){
    element.index = index;
});

sortData.sort(function(a,b) {
    var diff = a.weight - b.weight;
    return diff === 0 ? a.index - b.index : diff;
});

sortData.forEach(function(element){
    delete element.index;
});
pwolaq
  • 6,343
  • 19
  • 45
1

What you are looking for is a property of the sorting algorithm called stability. It means that the order of equally valued elements stays the same after sorting. The different browsers are using different algorithms for sorting, where some browsers use a stable and some use an unstable algorithm. You can see the difference between browsers on this SO thread: https://stackoverflow.com/a/3027715/1641070.

As you can see in the Ramda source, it uses the built-in sorting mechanism, so you get the same result if you use Ramda: https://github.com/ramda/ramda/blob/v0.22.1/src/sortBy.js#L38:L42

Community
  • 1
  • 1
Lukas_Skywalker
  • 2,053
  • 1
  • 16
  • 28
0

You may use underscore's _.sortBy(data,'weight') for stable sorting. check this

Shubham
  • 1,163
  • 2
  • 12
  • 36