GeekInTheBox
GeekInTheBox

Reputation: 149

Load a JSON document and sort it on one or more values in key:value pairs with JavaScript

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);
        }
    });
});

Upvotes: 0

Views: 79

Answers (1)

Roamer-1888
Roamer-1888

Reputation: 19288

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

Upvotes: 2

Related Questions