16

I have a few arrays of 50+ names like this.

["dan", "ryan", "bob", "steven", "corbin"]
["bob", "dan", "steven", "corbin"]

I have another array that has the correct order. Note that the second array above does not include all of the names, but I still want it to follow the order of the following:

["ryan", "corbin", "dan", "steven", "bob"]

There is no logical order to it, they are just in this order. What makes sense to me is to compare each array against the correctly ordered one. I think I saw some people doing this with PHP, but I was not able to find a JavaScript solution. Does anyone have any idea how to do this? I've been trying for a few hours and I'm stumped.

double-beep
  • 5,031
  • 17
  • 33
  • 41
Barry
  • 1,143
  • 2
  • 13
  • 26
  • Is there a specific reason reason you want them in that order? If you just want them in the *same* order you can just use `.sort()` on both of the arrays. – Aweary Feb 07 '15 at 01:35

5 Answers5

40

Use indexOf() to get the position of each element in the reference array, and use that in your comparison function.

var reference_array = ["ryan", "corbin", "dan", "steven", "bob"];
var array = ["bob", "dan", "steven", "corbin"];
array.sort(function(a, b) {
  return reference_array.indexOf(a) - reference_array.indexOf(b);
});
console.log(array); // ["corbin", "dan", "steven", "bob"]

Searching the reference array every time will be inefficient for large arrays. If this is a problem, you can convert it into an object that maps names to positions:

var reference_array = ["ryan", "corbin", "dan", "steven", "bob"];
reference_object = {};
for (var i = 0; i < reference_array.length; i++) {
    reference_object[reference_array[i]] = i;
}
var array = ["bob", "dan", "steven", "corbin"];
array.sort(function(a, b) {
  return reference_object[a] - reference_object[b];
});
console.log(array);
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • This works & answers the question I asked. I asked the question without saying my original array was actually an object. To fix this, I was able to get the keys from the object using `_.keys`, then I was able to sort them using your method `reference_array.indexOf(a) - reference_array.indexOf(b);` I asked a 2nd question with my exact code (http://stackoverflow.com/questions/28395477/javascript-sorting-parsed-json-within-each-loop), but in the end I had to figure out the conversion of object to array. I used this answer and the one over there to finally solve my sorting problem. – Barry Feb 09 '15 at 16:54
  • You should remember to tag your questions with `underscorejs` if you're interested in solutions using that library. – Barmar Feb 09 '15 at 18:28
1

You can realize some sorter by patter factory function. Then create sorter using your pattern and apply it to your arrays:

function sorterByPattern(pattern) {
    var hash = {};
    pattern.forEach(function(name, index) { hash[name] = index });

    return function(n1, n2) {
        if (!(n1 in hash)) return 1;  // checks if name is not in the pattern
        if (!(n2 in hash)) return -1; // if true - place that names to the end
        return hash[n1] - hash[n2];
    }
}

var sorter = sorterByPattern(["ryan", "corbin", "dan", "steven", "bob"]);

var arrays = [
    ["dan", "ryan", "bob", "steven", "corbin"],
    ["bob", "dan", "steven", "corbin"]
    /* ... */
];

arrays.forEach(function(array) { array.sort(sorter) });
alexpods
  • 47,475
  • 10
  • 100
  • 94
1

I had the same issue now and I tried a bit different approach. It does not sort the arrays but filtering the order-list according to sorting-lists so it has got some limitations but for my needs it's event better because it gets rid of incorrect values from sorted list:

  • if sorting-list has got doubled value, it will occure just once in sorted list
  • if sorting-list has got item which is not included in order-list, it will not appear in sorted list

function sortOrder(getOrder,getArr){
  return getOrder.filter(function(order){
    return getArr.some(function(list){
      return order === list;
    });
  });
}

//arrays
var order = ["ryan", "corbin", "dan", "steven", "bob"];
var arA = ["dan", "ryan", "bob", "steven", "corbin"];
var arB = ["bob", "dan", "steven", "corbin"];
var arC = ["bob","ryan"];
var arD = ["bob","bob","corbin"]; //remove repetition
var arE = ["unrecognizedItem","corbin","steven","ryan"]; //remove the item not included in order array

//print results
document.body.innerHTML = sortOrder(order,arA)+'<br/>';
document.body.innerHTML += sortOrder(order,arB)+'<br/>';
document.body.innerHTML += sortOrder(order,arC)+'<br/>';
document.body.innerHTML += sortOrder(order,arD)+'<br/>';
document.body.innerHTML += sortOrder(order,arE)+'<br/>';
Paweł
  • 4,238
  • 4
  • 21
  • 40
0

If you need to place values of your array in the recurring order, meaning:
Input: [1, 2, 4, 4, 3, 3, 2, 1]
Output: [1, 2, 3, 4, 1, 2, 3, 4]

Then you can use 2 functions below. The first one uses the second one.
For the first function you will need to provide 2 arguments:
1st argument: your array of items that should be ordered (Input from above)
2nd argument: array of the correct order ([1, 2, 3, 4] for the example above)

function sortByOrder (array, order) {

    const arrayOfArrays = order.map(v => {

        return [...Array(howMany(v, array))].map(undef => v);
    });

    const tempArray = [];

    arrayOfArrays.forEach((subArr, i) => {

        let index = order.indexOf(order[i]);

        subArr.forEach(duplicate => {

            tempArray[index] = duplicate;

            index += order.length;
        });
    });

    return tempArray.filter(v => v);
}

function howMany(value, array) {

        const regExp = new RegExp(value, 'g');

        return (array.join(' ').match(regExp) || []).length;
}
Eduard
  • 8,437
  • 10
  • 42
  • 64
0
var a = ["Senior", "Junior", "Intern", "Office Assistant"];
var b = ["Junior", "Cleaner", "Senior", "Intern", "Office Assistant"];

var res = [];

for (var i = 0; i < a.length; i++) {
  for (var j = 0; j < b.length; j++) {
    if (a[i] == b[j]) {
      res.push(b[j]);
      b.splice(b.indexOf(b[j]), 1)
      break;
    }
  }
}

console.log(res.concat(b)); // [ 'Senior', 'Junior', 'Intern', 'Office Assistant', 'Cleaner' ]
Fanisus
  • 13
  • 3