Javascript - diziyi başka bir diziye göre sırala


169

Şuna benzer bir diziyi sıralamak ve yeniden düzenlemek mümkün müdür:

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

bu dizinin düzeniyle eşleşmek için:

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

Maalesef, izlenecek hiçbir kimliğim yok. Mümkün olduğunca yakın sortingArr eşleştirmek için items-array öncelik gerekir.

Güncelleme:

İşte aradığım çıktı:

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

Bunun nasıl yapılabileceği hakkında bir fikrin var mı?


Her şeyi manuel olarak yapmak istemiyorsanız, sin PHP.js dizi işlevine bakın .
Adi

Sadece sortingArray üzerinde döngü yaparak ve öğeleri yeniden yazarakArray
mplungjan

6
Birden çok dizinin aynı sıralama değerine sahip olduğu yerlerde (yani 'b'), sıralanan dizide hangi öğenin nereye gittiğine nasıl karar verirsiniz? 'Bob', 'Henry' ve 'Thomas' ile hepsi 'b' değerine sahiptir - hangisinin birinci, üçüncü ve dördüncü olacağına nasıl karar verirsiniz?
Mitch Satchwell

@MitchS, soldan sağa okumaya öncelik vermek mümkün mü? Bu gerçek bir baş ağrısı, çünkü karşılaştırılacak kimliğim yok.
user1448892

Soldan sağa doğru, orijinal itemsArray'de göründükleri sırayı mı kastediyorsunuz?
Mitch Satchwell

Yanıtlar:


74

Gibi bir şey:

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

İşte daha kısa bir kod, ancak sortingdiziyi yok eder :

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

28
İkinci dereceden karmaşıklık! Büyük miktarda veriyle deneyin…
Julien Royer

6
@ thg435: veri hacminin küçük olacağı garanti edilmedikçe karmaşıklığın "optimizasyon" ile bir ilgisi yoktur (burada durum böyle olabilir).
Julien Royer

2
@georg Veri yapılarına etki eden algoritmaların karmaşıklığı söz konusu olduğunda, kuadratik (veya daha kötü) karmaşıklıklara sahip algoritmaların optimizasyonu asla erken değildir ve her zaman gereklidir (veri kümesinin boyutunun küçük olacağını garanti edemezseniz) . Performanstaki fark (tam anlamıyla) büyüklük sıralarıyla ifade edilir.
Abion47

238

Tek Satır yanıtı.

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

11
Bu değişecek itemsArray. Performans gereksinimine bağlı olarak, yapılması çok daha güvenli olacaktır itemsArray.slice().sort(...).
Sawtaytoes


8
Diziyi döndürür, ancak sıralamayı yerinde yapar ve orijinali değiştirir.
mynameistechno

2
Bu gerçek bir cevap olmalı
urmurmur

6
@Morvael, bunun nedeni sortingArr, içindeki tüm değerleri içermesi gereken bu yanıttır itemsArray. Düzeltme, öğeleri yoksa dizinin arkasına 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) ); });
itmektir

35

Yerel dizi sıralama işlevini kullanırsanız, diziyi sıralarken kullanılacak özel bir karşılaştırıcıyı iletebilirsiniz. İlk değer ikinciden küçükse karşılaştırıcı negatif, eşitse sıfır ve ilk değer büyükse pozitif bir sayı döndürmelidir.

Eğer doğru şekilde verdiğiniz örneği anlarsam, şöyle bir şey yapabilirsiniz:

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
Bu işe yaramaz, sonuçta elde edilen sıra indexOfilk dizini döndürdüğü gibi b, b, b, c, c, d olur .
Mitch Satchwell

Teşekkür ederim, ancak itemsArray çıktısının sortingArray ile eşleşmesini istiyorum.
user1448892

6
Ben de "kimlikleriyle" eğer bu cevabı tercih sortingArr, minnetle, onlar :) benim durumumda olan - benzersizdir
dillondrenzek

3
sortingArrayHer bir sıralama yinelemesinde yeniden bildirmekten
kaçınmak

26

Durum 1: Orijinal Soru (Kitaplık Yok)

İşe yarayan diğer cevaplar. :)

Durum 2: Orijinal Soru (Lodash.js veya Underscore.js)

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

Durum 3: Dizi1'i, Dizi2 gibi sırala

Çoğu kişi burada PHP dizi_multisort (ben yaptım) eşdeğer aramaya geldiğini tahmin ediyorum, bu yüzden ben de bu cevap göndereceğini düşündüm. Birkaç seçenek var:

1. array_multisort () öğesinin var olan bir JS uygulaması var . @Adnan'a yorumlarda işaret ettiği için teşekkürler. Yine de oldukça büyük.

2. Kendiniz yazın. ( JSFiddle demosu )

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 veya Underscore.js (hem performansa odaklanan hem popüler, daha küçük kütüphaneler) bunu yapmanızı sağlayan yardımcı işlevler sunar:

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

... Hangi (1) sortArray öğesini [index, value]çiftler halinde gruplandıracak , (2) bunları değere göre sıralayacaktır (burada bir geri arama da sağlayabilirsiniz), (3) çiftlerin her birini dizindeki itemArray öğesindeki öğeyle değiştirin çifti kökenlidir.


1
Mükemmel bir çözüm, alternatif olarak _.indexBy'yi kullanabilir ve veri
yapınız

20

bu muhtemelen çok geç, ancak aşağıdaki kodun bazı değiştirilmiş sürümlerini ES6 stilinde de kullanabilirsiniz. Bu kod aşağıdaki gibi diziler içindir:

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

Gerçek işlem:

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

ES5'teki gerçek işlem:

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

Sonuç vermeli arrayToBeSorted = [3,5]

Referans dizisini yok etmez.


4
ArrayToBeSorted bir Nesne Dizisi ise: {1: {…}, 2: {…}, 3: {…}, 4: {…}, 5: {…}}? Ancak arrayWithReferenceOrder sadece normal bir dizidir?
Kristal

3
@sushruth bu diziyi nasıl sıralar?
hitautodestruct

@Crystal, bu bir nesne, bir dizi nesne değil. Bir nesnedeki öğelerin / öğelerin sırası yoktur, yani sıraları ayarlanmamıştır. Bir dizi nesne şöyle görünecektir [{name: "1"}, {name: "2"}, {name: "3"}, ...].
JohnK

8

Bu itemsMapnedenle ikinci dereceden karmaşıklığı önleyerek bir aracı nesne ( ) kullanırdım :

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

Bkz. 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/

Sonuç emri: Bob, Jason, Henry, Thomas, Anne, Andrew


6

Neden böyle bir şey olmasın

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

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

Harita işlevi tüm sürümlerinde bulunmayabilir Javascript


1
Bu en temiz çözümdür ve cevap kabul edilmelidir. Teşekkürler!
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
Lütfen bu kodun soruyu neden / nasıl yanıtladığını açıklayan kısa bir açıklama / açıklama eklemeyi düşünün.
Yannis

3

Aradığım şey buydu ve başka bir Diziye dayalı bir Dizi Dizisi sıralamak için yaptım:

Açık ^ 3 ve en iyi uygulama olmayabilir (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));
Birine yardımcı olabilir


2

Bunu bir API'den aldığım JSON yükü için yapmak zorunda kaldım, ama istediğim sırada değildi.

Dizi başvuru dizisi, ikinci dizinin sıralama ölçütü olmasını istediğiniz dizidir:

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

Bunları nesne olarak yaptım çünkü sonunda başka özelliklere sahip olacaklar.

Oluşturulan dizi:

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

Bunu veritabanından sonuç kümesiyle birlikte kullandı. Ne kadar verimli olduğunu bilmiyorum ama kullandığım az sayıda sütunla işe yaradı.

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

Yeni bir sıralı dizi elde Mapetmek için, bir dizideki aranan anahtarla tüm öğeleri alabilir ve toplayabilir ve istenen grubun elenmiş öğesini alarak istenen sıralı anahtarları eşleyebilirsiniz.

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


MyBu benim favorim {}, Mapdo‍♂️ yerine aynı şeyi kullanıyorum
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;
})

Referans dizisinde sıralama anahtarı yoksa, bu çözüm en sonunda nesneleri ekler


0

bu çalışır:

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

Bu yöntemi deneyebilirsiniz.

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

Farklı giriş dizileriyle daha fazla örnek


0

Buraya bir dizi nesne ile ihtiyaç duymanız durumunda, @Durgpal Singh'in harika cevabının bir uyarlaması:

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'den $ .inArray () yöntemini kullanın. O zaman böyle bir şey yapabilirdin

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

İki dizinin kesişimini kullanın.

Ör:

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

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

_.intersection(sortArray, arrayToBeSort) 

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

'z ve' s 'ilk dizi aralığının dışındaysa, sonucun sonuna ekleyin


-4

Bunun gibi bir şey yapabilirsiniz:

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

Burada test edebilirsiniz .

Not: Bu, geçirdiğiniz dizilerin boyutunun eşdeğer olduğunu varsayar; durum böyle değilse ek denetimler eklemeniz gerekir.

bakınız linki

başvurmak


Bu kötü bir şekilde düzenlemeye ihtiyaç duyar. jfiddle sadece yanlış sonuç döndürmekle kalmaz, işlev bağımsız değişken adları iç içerikle eşleşmez mi?
twobob
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.