JavaScript-別の配列に基づいて配列をソートする


167

次のような配列を並べ替えて再配置することは可能ですか?

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をご覧ください
アディ

sortingArrayをループしてitemsArrayを書き直すことによってのみ
mplungjan

6
複数の配列が同じ並べ替え値(つまり 'b')を持っている場合、並べ替えられた配列のどこにどのアイテムを配置するかをどのように決定しますか?すべて「b」という値を持つ「ボブ」、「ヘンリー」、「トーマス」では、どのように最初、3番目、4番目に行くかをどのように決定しますか?
ミッチサッチウェル

@MitchS左から右に読むことを優先することは可能でしょうか?比較するIDがないので、これは本当に頭痛の種です。
user1448892

左から右へと、元のitemsArrayに表示される順序を意味しますか?
ミッチサッチウェル

回答:


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

27
二次の複雑さ!大量のデータでお試しください
Julien Royer

6
@ thg435:データ量が小さいことが保証されていない限り(ここではそうかもしれません)、複雑さは「最適化」とはほとんど関係ありません。
ジュリアンロイヤー

2
@georgデータ構造に作用するアルゴリズムの複雑さに関しては、2次(またはさらに悪い)複雑さを持つアルゴリズムの最適化は時期尚早ではなく、常に必要です(データセットのサイズが小さくなることが保証できない限り)。 。パフォーマンスの違いは、(文字通り)桁違いに表されます。
Abion47

236

1行回答。

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

10
これは変化しitemsArrayます。パフォーマンス要件によっては、実行する方がはるかに安全ですitemsArray.slice().sort(...)
Sawtaytoes


8
配列は返されますが、並べ替えも行われ、元の配列が変更されます。
mynameistechno 2018年

2
これは本当の答えでなければなりません
雑音

6
@Morvael、これは、この回答sortingArrがのすべての値を含める必要があるためitemsArrayです。修正は、以下に存在しない場合に項目を配列の後ろにプッシュすることですsortingArrallProducts.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

34

ネイティブ配列ソート関数を使用する場合、配列をソートするときに使用されるカスタムコンパレーターを渡すことができます。コンパレータは、最初の値が2番目の値より小さい場合は負の数を返し、等しい場合はゼロを返し、最初の値が大きい場合は正の数を返します。

したがって、私があなたが正しく与えている例を理解していれば、次のようなことができます:

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、最初のインデックスが返されます。
ミッチサッチウェル

ありがとうございましたが、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は単なる通常の配列ですか?
クリスタル

3
@sushruthこれはどのように配列を並べ替えますか?
hitautodestruct

@Crystal、それはオブジェクトであり、オブジェクトの配列ではありません。オブジェクトの要素/アイテムには順序がありません。つまり、それらの順序は設定されていません。オブジェクトの配列はのようになり[{name: "1"}, {name: "2"}, {name: "3"}, ...]ます。
JohnK

8

中間オブジェクト(itemsMap)を使用して、2次の複雑さを回避します。

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/

結果の順序:ボブ、ジェイソン、ヘンリー、トーマス、アン、アンドリュー


6

どうして

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

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

マップ機能は、すべてのバージョンで使用できるとは限りません Javascript


1
これは最もクリーンなソリューションであり、受け入れられるべき答えです。どうも!
ニューマン

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

これは私が探していたものであり、別の配列に基づいて配列の配列をソートするために行いました:

On ^ 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ペイロードに対してこれを行う必要がありましたが、望んだ順序ではありませんでした。

参照配列にする配列。2番目の配列を並べ替えるには、次のようにします。

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


hatそれが私のお気に入りです。同じことをし{}ますが、Mapyet️の代わりに使用します
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

2つの配列の共通部分を使用します。

例:

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.