0

I would like to sort a JSON array given a certain order from an array representing a name/value column. An example would be:

data = [
  {
     First: "John",
     Last: "Doe",
     Age: 23
  },
  {
     First: "Sue",
     Last: "San",
     Age: 13
  },
  {
     First: "Kyle",
     Last: "Wafer",
     Age: 87
  }
];
var sortBy = ["San", "Wafer", "Doe"];

So that my output would be:

  var newData = [
  {
     First: "Sue",
     Last: "San",
     Age: 13,
  },
  {
     First: "Kyle",
     Last: "Wafer",
     Age: 87,
  },

  {
     First: "John",
     Last: "Doe",
     Age: 23,
  }
];

Is it possible to implement using D3.js or basic JavaScript without complicated for loops? Thank you.

reptilicus
  • 10,290
  • 6
  • 55
  • 79
Finch
  • 297
  • 1
  • 2
  • 9

3 Answers3

2

You could use an object for the sort order and sort it by this values.

var data = [{ First: "John", Last: "Doe", Age: 23 }, { First: "Sue", Last: "San", Age: 13 }, { First: "Kyle", Last: "Wafer", Age: 87 }],
    sortBy = ["San", "Wafer", "Doe"],
    sortByObj = {};

sortBy.forEach(function (a, i) {
    sortByObj[a] = i + 1;
});

data.sort(function (a, b) {
    return (sortByObj[a.Last] || 0) - (sortByObj[b.Last] || 0);
});

console.log(data);
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
1

Can use the .sort() method on the array like so:

data.sort(function (a, b) {return sortBy.indexOf(a.Last) - sortBy.indexOf(b.Last)})
reptilicus
  • 10,290
  • 6
  • 55
  • 79
0

You can use sort and use indexOf to get the position, but that means on every sort you are doing an internal loop to get the position.

Without using sort, you can first index the elements via a key, than loop over the order.

data = [
  {
     First: "John",
     Last: "Doe",
     Age: 23
  },
  {
     First: "Sue",
     Last: "San",
     Age: 13
  },
  {
     First: "Kyle",
     Last: "Wafer",
     Age: 87
  }
];
var sortBy = ["San", "Wafer", "Doe"];

var temp = data.reduce( function(obj, item) {
    obj[item.Last] = item;
    return obj;
}, {});
var result = sortBy.map( function(key){ return temp[key]; });
console.log(result);

But where this technique would fail is it two keys would be duplicated. To get around that, it can be done with arrays.

data = [
  {
     First: "John",
     Last: "Doe",
     Age: 23
  },
  {
     First: "Jane",
     Last: "Doe",
     Age: 20
  },  
  {
     First: "Sue",
     Last: "San",
     Age: 13
  },
  {
     First: "Kyle",
     Last: "Wafer",
     Age: 87
  }
];
var sortBy = ["San", "Wafer", "Doe"];

var temp = data.reduce( function(obj, item) {
    if(!obj[item.Last]) obj[item.Last]=[];
    obj[item.Last].push(item);
    return obj;
}, {});
var result = sortBy.reduce( function(arr, item){ return arr.concat(temp[item]); return arr }, []);
console.log(result);

I am sure their is a fancier way of doing the concatenation, but did something quick.

You should run some performance tests based on your real data to see what performs the best.

epascarello
  • 204,599
  • 20
  • 195
  • 236