Подтвердить что ты не робот

Javascript - сортировать массив на основе другого массива

Можно ли отсортировать и переупорядочить массив, который выглядит так:

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

чтобы соответствовать расположению этого массива:

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

К сожалению, у меня нет идентификаторов для отслеживания. Мне нужно будет перенести массив items, чтобы он соответствовал сортировкеArr как можно ближе.

Update:

Вот результат, который я ищу:

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

Любая идея, как это можно сделать?

4b9b3361

Ответ 1

Что-то вроде:

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

Здесь более короткий код, но он уничтожает массив sorting:

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

Ответ 2

Ответ в одну строку.

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

Ответ 3

Если вы используете функцию сортировки собственного массива, вы можете перейти к произвольному компаратору, который будет использоваться при сортировке массива. Компаратор должен возвращать отрицательное число, если первое значение меньше второго, ноль, если они равны, и положительное число, если первое значение больше.

Итак, если я понимаю пример, который вы даете правильно, вы можете сделать что-то вроде:

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

itemsArray.sort(sortFunc);

Ответ 4

Случай 1: исходный вопрос (без библиотек)

Множество других ответов, которые работают.:)

Случай 2: исходный вопрос (Lodash.js или Underscore.js)

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

Случай 3: Сортировка массива1, как будто это Array2

Я предполагаю, что большинство людей пришли сюда искать эквивалент PHP array_multisort (я сделал), поэтому я думал, что тоже опубликую этот ответ. Есть несколько вариантов:

1. Там существует существующая реализация JS array_multisort(). Спасибо @Adnan за то, что вы указали это в комментариях. Он довольно большой.

2. Напишите свой собственный. (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 или Underscore.js (оба популярные, меньшие библиотеки, которые ориентированы на производительность) предлагают вспомогательные функции, которые позволяют это сделать:

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

... Который будет (1) группировать sortArray в пары [index, value], (2) сортировать их по значению (вы также можете предоставить обратный вызов здесь), (3) заменить каждую из пар на элемент из itemArray по индексу, из которого возникла пара.

Ответ 5

возможно, слишком поздно, но вы можете также использовать некоторую модифицированную версию кода ниже в стиле ES6. Этот код предназначен для таких массивов, как:

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

Фактическая операция:

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

Фактическая операция в ES5:

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

Должно получиться arrayToBeSorted = [3,5]

Не уничтожает ссылочный массив.

Ответ 6

Я бы использовал промежуточный объект (itemsMap), чтобы избежать квадратичной сложности:

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

Смотрите http://jsfiddle.net/eUskE/

Ответ 7

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/

Результирующий заказ: Боб, Джейсон, Генри, Томас, Энн, Эндрю

Ответ 8

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)

Ответ 9

Мне нужно было сделать это для полезной нагрузки JSON, которую я получаю от API, но это было не в том порядке, в котором я этого хотел.

Массив, который будет ссылочным массивом, тот, который вы хотите получить во втором массиве:

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"}
];

Я сделал это как объекты, потому что в конечном итоге они будут иметь другие свойства.

Созданный массив:

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

Используется с набором результатов из базы данных. Я не знаю, насколько это эффективно, но с небольшим количеством столбцов, которые я использовал, он работал нормально.

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

Ответ 10

Это то, что я искал и сделал для сортировки массива массивов на основе другого массива:

Это на ^ 3 и не может быть лучшей практикой (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));

Ответ 11

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

Это решение добавит объекты в конце, если сортировочный ключ отсутствует в ссылочном массиве.

Ответ 12

это должно работать:

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;

Ответ 13

Для получения нового упорядоченного массива вы можете взять Map и собрать все элементы с требуемым ключом в массиве и отобразить требуемые упорядоченные ключи, взяв просеянный элемент требуемой группы.

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

Ответ 14

Вы можете попробовать этот метод.

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
}

Ответ 15

Почему не что-то вроде

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

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

Функция карты может быть доступна не во всех версиях Javascript

Ответ 16

Используйте метод $.inArray() из jQuery. Тогда вы могли бы сделать что-то вроде этого

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

Ответ 17

Используйте пересечение двух массивов.

Пример:

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

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

_.intersection(sortArray, arrayToBeSort) 

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

если 'z и' s 'находятся вне диапазона первого массива, добавьте его в конец результата

Ответ 18

Вы можете сделать что-то вроде этого:

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

Здесь вы можете проверить его.

Примечание: это предполагает, что массивы, которые вы передаете, эквивалентны по размеру, вам нужно добавить дополнительные проверки, если это может быть не так.

отсылайте ссылку

обратитесь