0

I want to sort an array of objects based upon any of those object properties. But I want the original array left unchanged. Instead, I want to save the sort order of indexes in a separate array.

var source = [
  {"a": 2, "b": 8, "c": 9},
  {"a": 4, "b": 3, "c": 7},  
  {"a": 1, "b": 0, "c": 6}
]

var sortedIndexes;

SomeSortOfSortMethod("a", "asc");

// result of sortedIndexes containing indexes to source array:
// [2, 0, 1] 

Any ideas how to do this? I can't use the built in javascript sort method because it changes source. I need to just capture what the sort would be and save that order as indexes to the source arry.

risingtiger
  • 851
  • 1
  • 11
  • 21

2 Answers2

1

Make deep copy of initial array using array.map() and clone and apply sorting function over copied array.

The map() method creates a new array with the results of calling a provided function on every element in this array.

The sort() method sorts the elements of an array in place and returns the array.

Try this:

var source = [{
  "a": 2,
  "b": 8,
  "c": 9
}, {
  "a": 4,
  "b": 3,
  "c": 7
}, {
  "a": 1,
  "b": 0,
  "c": 6
}];

function clone(obj) {
  if (null == obj || "object" != typeof obj) return obj;
  var copy = obj.constructor();
  for (var attr in obj) {
    if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr];
  }
  return copy;
}
var temp = source.map(function(arr) {
  return clone(arr); //clone will make deep copy of the object
});
source[0].a = 50; //update the value from source object, it will not update `temp` array 
temp.sort(function(a, b) {
  return a.a - b.a; // `.a` will be the `key` to be sorted
});
snippet.log(JSON.stringify(temp));
snippet.log(JSON.stringify(source));
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
Community
  • 1
  • 1
Rayon
  • 36,219
  • 4
  • 49
  • 76
  • *map* doesn't make a "deep" copy, `var temp = source.slice()` gives the same result and is less to type. – RobG Feb 06 '16 at 04:03
  • @RobG, I got that wrong ;) Have updated the code with helper `clone` and added some comments too! I hope I am correct this time. Thank you for correcting me.. – Rayon Feb 06 '16 at 04:19
1
var source = [
      {"a": 2, "b": 8, "c": 9},
      {"a": 4, "b": 3, "c": 7},  
      {"a": 1, "b": 0, "c": 6}
    ];

var orderedCopyArray = _.sortBy(source, "a");

// Defualt ascending
console.log(JSON.stringify(orderedCopyArray));

// Descending
console.log(JSON.stringify(orderedCopyArray.reverse()));

var indexesArray = [], leng = source.length;

// Descending array ordered
var reverse = orderedCopyArray.reverse();

// Get index
for(var i=0; i < leng; i++){
  var obj1 = reverse[i]; 
  for(var j=0; j < leng; j++){
    var obj2 = source[j];
    if(_.isEqual(obj1, obj2)){
      indexesArray.push(j);
      break;
    }
  }
}

console.log(indexesArray); //[2, 0, 1]
ronIDX
  • 758
  • 1
  • 5
  • 20
  • 2
    That should be a comment, not an answer. – RobG Feb 06 '16 at 04:04
  • Mmmmm honestly in my opinion this is a valid alternative answer. Using external library is most of the times better than implement on your own a new one. – ronIDX Feb 06 '16 at 04:09
  • Because otherwise questions will be "answered" with suggestions to use libraries and not real answers. Imagine asking a DOM question and just getting answers like "use jQuery", "use Dojo", "use prototype.js"… – RobG Feb 06 '16 at 04:51
  • Ok, I added an example how do it wi UnderscoreJS – ronIDX Feb 06 '16 at 10:57
  • I agree RobG that questions can't be answered by just saying use such and such library. But I do appreciate ronIDX taking the time to explain the process through. – risingtiger Feb 07 '16 at 21:21
  • I am marking this as the answer because of the code explaining how to go through and figure out the indexes, which was the crux of what I was hoping to solve. So , thank you for that. So, I did make some mods though, cause the JSON.stringify was killing performance. I spliced the original array, thus making a new copy, but keeping references to the same objects. Now, I could compare object to object: much, much faster. – risingtiger Feb 07 '16 at 21:24
  • It may be informant to others out there if you did make that change, which ironically, would remove the need for underscore. So, instead of doing _.sortBy(source, "a"). Do: source.slice(). Then remove the JSON.stringify – risingtiger Feb 07 '16 at 21:27
  • I understand the slice() part, but not the object compare. I tried to compare directly Javascript Object, but return false always: [Javascript Object Compare](http://codepen.io/grimaldello/pen/yeRWJY?editors=1111). However feel free to edit my answer – ronIDX Feb 07 '16 at 21:33
  • Just discover this for objects compare: [Undescore.JS compare Javascript objects equality](http://underscorejs.org/#isEqual) – ronIDX Feb 07 '16 at 21:39
  • Modified answer to fits _.isEqual() method. Dunno performance for this method – ronIDX Feb 07 '16 at 21:46
  • That's much better performance wise to run the isEqual. Thanks for updating that. I'm still using the obj to obj compare which is working. But either way is viable. – risingtiger Feb 12 '16 at 00:59