0

I want to load an external JSON object and sort based on one or more key:value pairs. For example using the JSON below I might need to sort on category1 and then type.

I've tried array.sort() but no matter what I throw at it my data is never sorted; It's always output in the same order as in the JSON file.

{
  "books": [
    {
      "sku": "{1234}",
      "title": "Moby Dick",
      "type": "paperback",
      "category1": "fiction",
      "category2": "classic",
      "category3": "",
      "image": "",
      "ctaLabel": "Learn More"
    },
    {
      "sku": "{5678}",
      "title": "1984",
      "type": "hardcover",
      "category1": "fiction",
      "category2": "",
      "category3": "",
      "image": "",
      "ctaLabel": "Learn More"
    },
    {
      "sku": "{5678}",
      "title": "Another Title",
      "type": "paperback",
      "category1": "nonfiction",
      "category2": "youngadult",
      "category3": "",
      "image": "",
      "ctaLabel": "Learn More"
    }
  ]
}

 

$(function() {
    $.getJSON('books.json', function (data) {
        console.log(data);
        var items = data.books.map(function (item) {
            return item.sku + ': ' + item.title;
        });
        if (items.length) {
            var content = '<li>' + items.join('</li><li>') + '</li>';
            var list = $('<ul />').html(content);
            $("#show-data").html(list);
        }
    });
});
Alexis Tyler
  • 1,394
  • 6
  • 30
  • 48
GeekInTheBox
  • 139
  • 2
  • 11
  • Look at this post. http://stackoverflow.com/questions/15047801/re-order-json-array-by-key-value – Chris Sharp Feb 01 '17 at 23:48
  • 1
    I generally don't do this because you have specified javascript/jquery in the tags, but a library like Lodash would help you tremendously if you can use it. – Brandon Feb 01 '17 at 23:56

1 Answers1

2

Based on this answer, you can implement a multi-level sort as follows :

function multiLevelSort(arr, criteria) {
    return arr.sort(function(x, y) {
        return criteria.reduce(function(prev, curr) {
            var dir = (curr.dir < 0) ? -1 : 1,
                x_ = x[curr.prop],
                y_ = y[curr.prop];
            return prev || (x_ === y_ ? 0 : x_ > y_ ? dir : -dir);
        }, 0);
    });
}

or, with destructuring (in Node but not yet in all browsers) :

function multiLevelSort(arr, criteria) {
    return arr.sort(function(x, y) {
        return criteria.reduce(function(prev, {prop, dir}) {
            dir = (dir < 0) ? -1 : 1;
            var x_ = x[prop],
                y_ = y[prop];
            return prev || (x_ === y_ ? 0 : x_ > y_ ? dir : -dir);
        }, 0);
    });
}

where :

  • arr is an array of objects, as in the question.
  • criteria is an array of objects of the following format :
var criteria = [
    {prop: "type", dir: 1}, // dir:1=ascending; dir:-1=descending
    {prop: "category1", dir: 1}, 
    {prop: "category2", dir: 1} 
];

Then simply call :

multiLevelSort(myArray, myCriteria);

Like Array.prototype.sort(), myArray will be mutated and returned.

DEMO

Community
  • 1
  • 1
Roamer-1888
  • 19,138
  • 5
  • 33
  • 44
  • one quick question...what if I want to return _all_ elements and their values for each member regardless of how many sort criteria I specify? – GeekInTheBox Feb 03 '17 at 16:24
  • That is exactly how `multiLevelSort()` already behaves - it sorts, not filters. In the demo, you see only columns `type`, `category1` and `category2` because these are everything necessary for demonstration. In the sorted array, all the original objects are still 100% intact, just in a different order. – Roamer-1888 Feb 03 '17 at 16:36