Javascript - sort array based on another array

Javascript

Javascript Problem Overview


Is it possible to sort and rearrange an array that looks like this:

itemsArray = [     ['Anne', 'a'],
    ['Bob', 'b'],
    ['Henry', 'b'],
    ['Andrew', 'd'],
    ['Jason', 'c'],
    ['Thomas', 'b']
]

to match the arrangement of this array:

sortingArr = [ 'b', 'c', 'b', 'b', 'a', 'd' ]

Unfortunately, I don’t have any IDs to keep track on. I would need to priority the items-array to match the sortingArr as close as possible.

Update:

Here is the output I’m looking for:

itemsArray = [        ['Bob', 'b'],
    ['Jason', 'c'],
    ['Henry', 'b'],
    ['Thomas', 'b']
    ['Anne', 'a'],
    ['Andrew', 'd'],
]

Any idea how this can be done?

Javascript Solutions


Solution 1 - Javascript

One-Line answer.

itemsArray.sort(function(a, b){
return sortingArr.indexOf(a) - sortingArr.indexOf(b); });

Or even shorter: itemsArray.sort((a, b) => sortingArr.indexOf(a) - sortingArr.indexOf(b));

Solution 2 - Javascript

Something like:

items = [ 
    ['Anne', 'a'],
    ['Bob', 'b'],
    ['Henry', 'b'],
    ['Andrew', 'd'],
    ['Jason', 'c'],
    ['Thomas', 'b']
]

sorting = [ 'b', 'c', 'b', 'b', 'c', 'd' ];
result = []

sorting.forEach(function(key) {
	var found = false;
	items = items.filter(function(item) {
		if(!found && item[1] == key) {
			result.push(item);
			found = true;
			return false;
		} else 
			return true;
	})
})

result.forEach(function(item) {
	document.writeln(item[0]) /// Bob Jason Henry Thomas Andrew
})

Here's a shorter code, but it destroys the sorting array:

result = items.map(function(item) {
	var n = sorting.indexOf(item[1]);
	sorting[n] = '';
	return [n, item]
}).sort().map(function(j) { return j[1] })

Solution 3 - Javascript

If you use the native array sort function, you can pass in a custom comparator to be used when sorting the array. The comparator should return a negative number if the first value is less than the second, zero if they're equal, and a positive number if the first value is greater.

So if I understand the example you're giving correctly, you could do something like:

function sortFunc(a, b) {
  var sortingArr = [ 'b', 'c', 'b', 'b', 'c', 'd' ];
  return sortingArr.indexOf(a[1]) - sortingArr.indexOf(b[1]);
}

itemsArray.sort(sortFunc);

Solution 4 - Javascript

Case 1: Original Question (No Libraries)

Plenty of other answers that work. :)

Case 2: Original Question (Lodash.js or Underscore.js)

var groups = _.groupBy(itemArray, 1);
var result = _.map(sortArray, function (i) { return groups[i].shift(); });

Case 3: Sort Array1 as if it were Array2

I'm guessing that most people came here looking for an equivalent to PHP's array_multisort (I did) so I thought I'd post that answer as well. There are a couple options:

1. There's an existing JS implementation of array_multisort(). Thanks to @Adnan for pointing it out in the comments. It is pretty large, though.

2. Write your own. (JSFiddle demo)

function refSort (targetData, refData) {
  // Create an array of indices [0, 1, 2, ...N].
  var indices = Object.keys(refData);

  // Sort array of indices according to the reference data.
  indices.sort(function(indexA, indexB) {
    if (refData[indexA] < refData[indexB]) {
      return -1;
    } else if (refData[indexA] > refData[indexB]) {
      return 1;
    }
    return 0;
  });

  // Map array of indices to corresponding values of the target array.
  return indices.map(function(index) {
    return targetData[index];
  });
}

3. Lodash.js or Underscore.js (both popular, smaller libraries that focus on performance) offer helper functions that allow you to do this:

    var result = _.chain(sortArray)
      .pairs()
      .sortBy(1)
      .map(function (i) { return itemArray[i[0]]; })
      .value();

...Which will (1) group the sortArray into [index, value] pairs, (2) sort them by the value (you can also provide a callback here), (3) replace each of the pairs with the item from the itemArray at the index the pair originated from.

Solution 5 - Javascript

this is probably too late but, you could also use some modified version of the code below in ES6 style. This code is for arrays like:

var arrayToBeSorted = [1,2,3,4,5];
var arrayWithReferenceOrder = [3,5,8,9];

The actual operation :

arrayToBeSorted = arrayWithReferenceOrder.filter(v => arrayToBeSorted.includes(v));

The actual operation in ES5 :

arrayToBeSorted = arrayWithReferenceOrder.filter(function(v) {
    return arrayToBeSorted.includes(v);
});

Should result in arrayToBeSorted = [3,5]

Does not destroy the reference array.

Solution 6 - Javascript

Why not something like

//array1: array of elements to be sorted
//array2: array with the indexes

array1 = array2.map((object, i) => array1[object]);

The map function may not be available on all versions of Javascript

Solution 7 - Javascript

function sortFunc(a, b) {
  var sortingArr = ["A", "B", "C"];
  return sortingArr.indexOf(a.type) - sortingArr.indexOf(b.type);
}

const itemsArray = [
  {
    type: "A",
  },
  {
    type: "C",
  },
  {
    type: "B",
  },
];
console.log(itemsArray);
itemsArray.sort(sortFunc);
console.log(itemsArray);

Solution 8 - Javascript

I would use an intermediary object (itemsMap), thus avoiding quadratic complexity:

function createItemsMap(itemsArray) { // {"a": ["Anne"], "b": ["Bob", "Henry"], …}
  var itemsMap = {};
  for (var i = 0, item; (item = itemsArray[i]); ++i) {
    (itemsMap[item[1]] || (itemsMap[item[1]] = [])).push(item[0]);
  }
  return itemsMap;
}

function sortByKeys(itemsArray, sortingArr) {
  var itemsMap = createItemsMap(itemsArray), result = [];
  for (var i = 0; i < sortingArr.length; ++i) {
    var key = sortingArr[i];
    result.push([itemsMap[key].shift(), key]);
  }
  return result;
}

See http://jsfiddle.net/eUskE/

Solution 9 - Javascript

ES6

const arrayMap = itemsArray.reduce(
  (accumulator, currentValue) => ({
    ...accumulator,
    [currentValue[1]]: currentValue,
  }),
  {}
);
const result = sortingArr.map(key => arrayMap[key]);

More examples with different input arrays

Solution 10 - Javascript

var sortedArray = [];
for(var i=0; i < sortingArr.length; i++) {
    var found = false;
    for(var j=0; j < itemsArray.length && !found; j++) {
        if(itemsArray[j][1] == sortingArr[i]) {
            sortedArray.push(itemsArray[j]);
            itemsArray.splice(j,1);
            found = true;
        }
    }
}

http://jsfiddle.net/s7b2P/

Resulting order: Bob,Jason,Henry,Thomas,Anne,Andrew

Solution 11 - Javascript

In case you get here needing to do this with an array of objects, here is an adaptation of @Durgpal Singh's awesome answer:

const itemsArray = [
  { name: 'Anne', id: 'a' },
  { name: 'Bob', id: 'b' },
  { name: 'Henry', id: 'b' },
  { name: 'Andrew', id: 'd' },
  { name: 'Jason', id: 'c' },
  { name: 'Thomas', id: 'b' }
]

const sortingArr = [ 'b', 'c', 'b', 'b', 'a', 'd' ]

Object.keys(itemsArray).sort((a, b) => {
  return sortingArr.indexOf(itemsArray[a].id) - sortingArr.indexOf(itemsArray[b].id);
})

Solution 12 - Javascript

let a = ['A', 'B', 'C' ]

let b = [3, 2, 1]

let c = [1.0, 5.0, 2.0]

// these array can be sorted by sorting order of b

const zip = rows => rows[0].map((_, c) => rows.map(row => row[c]))

const sortBy = (a, b, c) => {
  const zippedArray = zip([a, b, c])
  const sortedZipped = zippedArray.sort((x, y) => x[1] - y[1])

  return zip(sortedZipped)
}

sortBy(a, b, c)

Solution 13 - Javascript

This is what I was looking for and I did for sorting an Array of Arrays based on another Array:

> It's On^3 and might not be the best practice(ES6)

function sortArray(arr, arr1){
      return arr.map(item => {
        let a = [];
        for(let i=0; i< arr1.length; i++){
          for (const el of item) {
            if(el == arr1[i]){
              a.push(el);
            }   
            }
          }
          return a;
      });
    }
    
    const arr1 = ['fname', 'city', 'name'];
  const arr = [['fname', 'city', 'name'],
  ['fname', 'city', 'name', 'name', 'city','fname']];
  console.log(sortArray(arr,arr1));

It might help someone

Solution 14 - Javascript

For getting a new ordered array, you could take a Map and collect all items with the wanted key in an array and map the wanted ordered keys by taking sifted element of the wanted group.

var itemsArray = [['Anne', 'a'], ['Bob', 'b'], ['Henry', 'b'], ['Andrew', 'd'], ['Jason', 'c'], ['Thomas', 'b']], sortingArr = [ 'b', 'c', 'b', 'b', 'a', 'd' ], map = itemsArray.reduce((m, a) => m.set(a[1], (m.get(a[1]) || []).concat([a])), new Map), result = sortingArr.map(k => (map.get(k) || []).shift());

console.log(result);

Solution 15 - Javascript

I had to do this for a JSON payload I receive from an API, but it wasn't in the order I wanted it.

Array to be the reference array, the one you want the second array sorted by:

var columns = [    {last_name: "last_name"},    {first_name: "first_name"},    {book_description: "book_description"},    {book_id: "book_id"},    {book_number: "book_number"},    {due_date: "due_date"},    {loaned_out: "loaned_out"}];

I did these as objects because these will have other properties eventually.

Created array:

 var referenceArray= [];
 for (var key in columns) {
     for (var j in columns[key]){
         referenceArray.push(j);
     }
  }

Used this with result set from database. I don't know how efficient it is but with the few number of columns I used, it worked fine.

result.forEach((element, index, array) => {                            
	var tr = document.createElement('tr');
	for (var i = 0; i < referenceArray.length - 1; i++) {
		var td = document.createElement('td');
		td.innerHTML = element[referenceArray[i]];
		tr.appendChild(td);

	}
	tableBody.appendChild(tr);
}); 

Solution 16 - Javascript

let sortedOrder = [ 'b', 'c', 'b', 'b' ]
let itemsArray = [ 
    ['Anne', 'a'],
    ['Bob', 'b'],
    ['Henry', 'b'],
    ['Andrew', 'd'],
    ['Jason', 'c'],
    ['Thomas', 'b']
]
a.itemsArray(function (a, b) {
    let A = a[1]
    let B = b[1]

    if(A != undefined)
        A = A.toLowerCase()

    if(B != undefined)
        B = B.toLowerCase()

    let indA = sortedOrder.indexOf(A)
    let indB = sortedOrder.indexOf(B)

    if (indA == -1 )
        indA = sortedOrder.length-1
    if( indB == -1)
        indB = sortedOrder.length-1

    if (indA < indB ) {
        return -1;
    } else if (indA > indB) {
        return 1;
    }
    return 0;
})

This solution will append the objects at the end if the sorting key is not present in reference array

Solution 17 - Javascript

  const result = sortingArr.map((i) => {
    const pos = itemsArray.findIndex(j => j[1] === i);
    const item = itemsArray[pos];
    itemsArray.splice(pos, 1);
    return item;
  });

Solution 18 - Javascript

this should works:

var i,search, itemsArraySorted = [];
while(sortingArr.length) {
	search = sortingArr.shift();
	for(i = 0; i<itemsArray.length; i++) {
		if(itemsArray[i][1] == search) {
			itemsArraySorted.push(itemsArray[i]);
			break;
		}
	} 
}

itemsArray = itemsArraySorted;

Solution 19 - Javascript

You could try this method.

const sortListByRanking = (rankingList, listToSort) => {
  let result = []

  for (let id of rankingList) {
    for (let item of listToSort) {
      if (item && item[1] === id) {
        result.push(item)
      }
    }
  }

  return result
}

Solution 20 - Javascript

with numerical sortingArr:

itemsArray.sort(function(a, b){  
  return sortingArr[itemsArray.indexOf(a)] - sortingArr[itemsArray.indexOf(b)];
});

Solution 21 - Javascript

This seems to work for me:

var outputArray=['10','6','8','10','4','6','2','10','4','0','2','10','0'];
var template=['0','2','4','6','8','10'];
var temp=[];

for(i=0;i<template.length;i++) {
  for(x=0;x<outputArray.length;x++){
    if(template[i] == outputArray[x]) temp.push(outputArray[x])
  };
}

outputArray = temp;
alert(outputArray)

Solution 22 - Javascript

Use the $.inArray() method from jQuery. You then could do something like this

var sortingArr = [ 'b', 'c', 'b', 'b', 'c', 'd' ];
var newSortedArray = new Array();

for(var i=sortingArr.length; i--;) {
 var foundIn = $.inArray(sortingArr[i], itemsArray);
 newSortedArray.push(itemsArray[foundIn]);
}

Solution 23 - Javascript

Use intersection of two arrays.

Ex:

var sortArray = ['a', 'b', 'c',  'd', 'e'];

var arrayToBeSort = ['z', 's', 'b',  'e', 'a'];

_.intersection(sortArray, arrayToBeSort) 

=> ['a', 'b', 'e']

if 'z and 's' are out of range of first array, append it at the end of result

Solution 24 - Javascript

this.arrToBeSorted =  this.arrToBeSorted.sort(function(a, b){  
  return uppthis.sorrtingByArray.findIndex(x => x.Id == a.ByPramaeterSorted) - uppthis.sorrtingByArray.findIndex(x => x.Id == b.ByPramaeterSorted);
});

Solution 25 - Javascript

You can do something like this:

function getSorted(itemsArray , sortingArr ) {
  var result = [];
  for(var i=0; i<arr.length; i++) {
    result[i] = arr[sortArr[i]];
  }
  return result;
}

You can test it out here.

Note: this assumes the arrays you pass in are equivalent in size, you'd need to add some additional checks if this may not be the case.

refer link

refer

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser1448892View Question on Stackoverflow
Solution 1 - JavascriptDurgpal SinghView Answer on Stackoverflow
Solution 2 - JavascriptgeorgView Answer on Stackoverflow
Solution 3 - JavascriptDavid LewisView Answer on Stackoverflow
Solution 4 - JavascriptDon McCurdyView Answer on Stackoverflow
Solution 5 - JavascriptSushruthView Answer on Stackoverflow
Solution 6 - JavascriptLuca Di LielloView Answer on Stackoverflow
Solution 7 - JavascriptDebabrata NayakView Answer on Stackoverflow
Solution 8 - JavascriptJulien RoyerView Answer on Stackoverflow
Solution 9 - JavascriptCan RauView Answer on Stackoverflow
Solution 10 - JavascriptMitch SatchwellView Answer on Stackoverflow
Solution 11 - Javascriptuser2521295View Answer on Stackoverflow
Solution 12 - JavascriptHarshal PatilView Answer on Stackoverflow
Solution 13 - JavascriptEl.View Answer on Stackoverflow
Solution 14 - JavascriptNina ScholzView Answer on Stackoverflow
Solution 15 - JavascriptjohnnyView Answer on Stackoverflow
Solution 16 - JavascriptJD-VView Answer on Stackoverflow
Solution 17 - JavascriptPacuraru DanielView Answer on Stackoverflow
Solution 18 - JavascriptLuca RainoneView Answer on Stackoverflow
Solution 19 - JavascriptHolger TidemandView Answer on Stackoverflow
Solution 20 - JavascriptnikoView Answer on Stackoverflow
Solution 21 - JavascriptHowardView Answer on Stackoverflow
Solution 22 - Javascripttoxicate20View Answer on Stackoverflow
Solution 23 - JavascriptJoe.CKView Answer on Stackoverflow
Solution 24 - JavascriptintegraterView Answer on Stackoverflow
Solution 25 - JavascriptGaddeView Answer on Stackoverflow