자바 스크립트-다른 배열을 기준으로 배열 정렬


169

다음과 같은 배열을 정렬하고 재 배열 할 수 있습니까?

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

이 배열의 배열과 일치합니다.

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

유감스럽게도 추적 할 ID가 없습니다. sortingArr과 최대한 일치하도록 items-array의 우선 순위를 지정해야합니다.

최신 정보:

내가 찾고있는 출력은 다음과 같습니다.

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

이것이 어떻게 이루어질 수 있는지 아십니까?


모든 것을 수동으로 수행하지 않으려면 배열 함수 sin PHP.js를 살펴보십시오 .
Adi

만 itemsArray을 sortingArray 이상 반복하고 다시 작성하여
mplungjan

6
여러 배열이 동일한 정렬 값을 갖는 경우 (예 : 'b') 정렬 된 배열에서 어떤 항목이 어디로 갈지 어떻게 결정합니까? 'Bob', 'Henry'및 'Thomas'를 사용하면 모두 'b'라는 값을 갖습니다. 첫 번째, 세 번째 및 네 번째로가는 값은 어떻게 결정합니까?
Mitch Satchwell

@MitchS 왼쪽에서 오른쪽으로 읽기 우선 순위를 지정할 수 있습니까? 비교할 ID가 없기 때문에 이것은 두통입니다.
user1448892

왼쪽에서 오른쪽은 원래 itemsArray에 나타나는 순서를 의미합니까?
Mitch Satchwell

답변:


74

다음과 같은 것 :

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

28
이차 복잡성! ... 데이터의 큰 양을보십시오
줄리앙 이어에게

6
@ thg435 : 데이터의 양이 작을 경우를 제외하고 복잡성은 "최적화"와 거의 관련이 없습니다.
Julien Royer

2
@georg 데이터 구조에 작용하는 알고리즘의 복잡성과 관련하여 2 차 (또는 더 나쁜) 복잡성을 가진 알고리즘의 최적화는 결코 조기에 이루어지지 않으며 항상 필요합니다 (데이터 세트의 크기가 작다는 것을 보장 할 수 없다면) . 성능의 차이는 문자 그대로 매우 큰 순서로 표현됩니다.
Abion47

237

한 줄 답변.

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

11
이 변경 itemsArray됩니다. 성능 요구 사항에 따라 수행하는 것이 훨씬 안전합니다 itemsArray.slice().sort(...).
Sawtaytoes

1
sort 메소드는 배열을 리턴합니다. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Durgpal Singh

8
배열을 반환하지만 정렬도 수행하고 원본을 변경합니다.
mynameistechno

2
이것은 실제 답변이어야합니다
urmurmur

6
@ Morvael, 이것은이 답변이 sortingArr에 모든 값을 포함 해야 하기 때문 입니다 itemsArray. 해결 방법은 다음 항목이없는 경우 항목을 배열의 뒷면으로 푸시하는 것입니다 sortingArr.allProducts.sort((product1, product2) => { const index1 = manualSort.indexOf(product1.id); const index2 = manualSort.indexOf(product2.id); return ( (index1 > -1 ? index1 : Infinity) - (index2 > -1 ? index2 : Infinity) ); });
Freshollie

35

기본 배열 정렬 기능을 사용하는 경우 배열을 정렬 할 때 사용할 사용자 정의 비교기를 전달할 수 있습니다. 비교기는 첫 번째 값이 두 번째 값보다 작 으면 음수를 반환하고, 같으면 0을, 첫 번째 값이 큰 경우 양수를 반환해야합니다.

따라서 올바르게 제공 한 예를 이해하면 다음과 같이 할 수 있습니다.

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

itemsArray.sort(sortFunc);

3
작동하지 않으면 결과 순서는 b, b, b, c, c, d indexOf이며 첫 번째 인덱스 를 반환합니다.
Mitch Satchwell

고맙지 만 itemsArray의 출력이 sortingArray와 일치하도록하고 싶습니다.
user1448892

6
나는에서 "ID를"경우이 대답 선호 sortingArr다행히도, 그들은 : 내 경우에 - 고유
dillondrenzek

3
당신은 선언해야 sortingArrayavoir에 함수의 외부를 각각 정렬 반복에 그것을 다시 선언
aurumpotestasest

26

사례 1 : 원래 질문 (라이브러리 없음)

작동하는 다른 답변이 많이 있습니다. :)

사례 2 : 원래 질문 (Lodash.js 또는 Underscore.js)

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

사례 3 : Array1을 Array2 인 것처럼 정렬

나는 대부분의 사람들이 PHP의 array_multisort (내가 한)와 동등한 것을 찾고 여기에 왔기 때문에 그 대답을 게시 할 것이라고 생각했습니다. 몇 가지 옵션이 있습니다.

1. array_multisort () 의 기존 JS 구현이 있습니다. 의견에서 지적한 @Adnan에게 감사합니다. 그래도 꽤 큽니다.

2. 직접 작성하십시오. ( JSFiddle 데모 )

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 항목으로 바꿉니다. 쌍에서 유래.


1
훌륭한 해결책, 또는 _.indexBy를 사용하고 데이터 구조가 좀 더 복잡한 경우 변화를 제거 할 수 있습니다.
Frozenfire

20

이것은 아마도 너무 늦었지만 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]

참조 배열을 파괴하지 않습니다.


4
arrayToBeSorted가 객체의 배열 인 경우 어떻게해야합니까? 예 : {1 : {…}, 2 : {…}, 3 : {…}, 4 : {…}, 5 : {…}}? 그러나 arrayWithReferenceOrder는 단지 정상적인 배열입니까?
Crystal

3
@ sushruth 이것은 배열을 어떻게 정렬합니까?
hitautodestruct 오전

@Crystal, 그것은 객체의 배열이 아닌 객체입니다. 객체의 요소 / 항목에는 순서가 없습니다. 즉 순서가 설정되지 않은 것입니다. 객체 배열은 다음과 같습니다 [{name: "1"}, {name: "2"}, {name: "3"}, ...].
JohnK

8

중간 객체 ( 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/ 참조


6
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/

결과 주문 : Bob, Jason, Henry, Thomas, Anne, Andrew


6

왜 안돼

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

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

모든 버전의지도에서지도 기능을 사용하지 못할 수 있습니다. Javascript


1
이것은 가장 깨끗한 해결책이며, 대답이 받아 들여 져야합니다. 고마워!
newman

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

2
이 코드가 질문에 대답하는 이유 / 방법을 설명하는 간단한 설명 / 설명을 추가하십시오.
Yannis

3

이것은 내가 찾고 있었고 다른 배열을 기반으로 배열 배열을 정렬하려고했습니다.

켜짐 ^ 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));
누군가를 도울 수 있습니다


2

API에서받은 JSON 페이로드에 대해이 작업을 수행해야했지만 원하는 순서는 아닙니다.

배열은 참조 배열이며 두 번째 배열을 정렬하려는 배열은 다음과 같습니다.

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

2

새로운 정렬 배열을 얻으 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);


👏 저의 마음 {}Map드는 것입니다. 🤷‍♂️
Can Rau

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

정렬 키가 참조 배열에 없으면이 솔루션은 끝에 객체를 추가합니다.


0

이것은 작동해야합니다 :

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;

0

이 방법을 시도해 볼 수 있습니다.

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
}

0

ES6

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

다른 입력 배열을 가진 더 많은 예제


0

객체 배열을 사용 하여이 작업을 수행 해야하는 경우 @Durgpal Singh의 멋진 답변을 다음과 같이 수정했습니다.

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

-1

jQuery에서 $ .inArray () 메소드를 사용하십시오. 그런 다음 이런 식으로 할 수 있습니다

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

-1

두 배열의 교집합을 사용하십시오.

전의:

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

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

_.intersection(sortArray, arrayToBeSort) 

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

'z 및's '가 첫 번째 배열 범위를 벗어나면 결과 끝에 추가하십시오.


-4

다음과 같이 할 수 있습니다 :

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

여기서 테스트 할 수 있습니다 .

참고 : 이것은 전달하는 배열의 크기가 동일하다고 가정하므로 그렇지 않은 경우 추가 검사를 추가해야합니다.

링크 참조

보내다


편집이 절실히 필요합니다. jfiddle은 잘못된 결과를 반환 할뿐만 아니라 함수 인수 이름이 내부 내용과 일치하지 않습니까?
twobob
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.