Javascript - array เรียงลำดับตามอาร์เรย์อื่น


169

เป็นไปได้ไหมที่จะเรียงลำดับและจัดเรียงอาร์เรย์ใหม่ที่มีลักษณะดังนี้:

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

เพื่อให้ตรงกับการจัดเรียงของอาร์เรย์นี้:

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

น่าเสียดายที่ฉันไม่มีรหัสใด ๆ ที่จะติดตาม ฉันจะต้องจัดลำดับความสำคัญรายการอาร์เรย์เพื่อให้ตรงกับ sortingArr ใกล้ที่สุด

ปรับปรุง:

นี่คือผลลัพธ์ที่ฉันกำลังมองหา:

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

มีความคิดว่าจะทำสิ่งนี้ได้อย่างไร?


หากคุณไม่ต้องการที่จะทำทุกอย่างด้วยตนเองให้ดูที่ฟังก์ชั่นอาร์เรย์บาปPHP.js
Adi

เฉพาะการวนลูปมากกว่า sortingArray และเขียน itemsArray อีกครั้ง
mplungjan

6
ที่หลายอาร์เรย์มีค่าการเรียงลำดับเหมือนกัน (เช่น 'b') คุณจะตัดสินใจได้อย่างไรว่ารายการใดจะไปอยู่ที่ไหนในอาร์เรย์ที่เรียงลำดับ ด้วย 'Bob', 'Henry' และ 'Thomas' ซึ่งทั้งหมดมีค่า 'b' - คุณจะตัดสินใจได้อย่างไรว่าจะเลือกที่หนึ่งอันดับสามและสี่
Mitch Satchwell

@MitchS เป็นไปได้ไหมที่จะจัดลำดับความสำคัญการอ่านจากซ้ายไปขวา นี่เป็นอาการปวดหัวอย่างแท้จริงเนื่องจากฉันไม่มีรหัสที่จะเปรียบเทียบ
user1448892

คุณหมายถึงคำสั่งซื้อที่ปรากฏในรายการต้นฉบับจากซ้ายไปขวาหมายความว่าอย่างไร
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
ความซับซ้อนกำลังสอง! ลองกับจำนวนเงินที่ใหญ่ของข้อมูล ...
Julien Royer

6
@ thg435: ความซับซ้อนนั้นมีส่วนเกี่ยวข้องกับ "การปรับให้เหมาะสม" เพียงเล็กน้อยเว้นแต่ว่าปริมาณข้อมูลจะมีขนาดเล็ก (ซึ่งอาจเป็นกรณีนี้)
Julien Royer

2
@georg เมื่อพูดถึงความซับซ้อนของอัลกอริธึมที่ทำหน้าที่เกี่ยวกับโครงสร้างข้อมูลการเพิ่มประสิทธิภาพของอัลกอริธึมที่มีความซับซ้อนเป็นกำลังสอง (หรือแย่กว่า) นั้นไม่เคยเกิดก่อนกำหนดและจำเป็นเสมอ (เว้นแต่ว่าคุณจะรับประกันขนาดของชุดข้อมูล . ความแตกต่างในการทำงานคือ (ตามตัวอักษร) แสดงตามลำดับความสำคัญ
Abion47

238

คำตอบหนึ่งบรรทัด

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

11
itemsArrayนี้จะกลายพันธุ์ itemsArray.slice().sort(...)ทั้งนี้ขึ้นอยู่กับความต้องการประสิทธิภาพการทำงานก็จะมีความปลอดภัยมากที่จะทำ
Sawtaytoes

1
วิธีการเรียงลำดับส่งกลับอาร์เรย์ ดูdeveloper.mozilla.org/en-US/docs/Web/JavaScript/Reference/
......

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

หากคุณใช้ฟังก์ชั่นการจัดเรียงอาร์เรย์แบบเนทิฟคุณสามารถส่งผ่านตัวเปรียบเทียบแบบกำหนดเองที่จะใช้เมื่อเรียงลำดับอาร์เรย์ ผู้เปรียบเทียบควรคืนค่าจำนวนลบหากค่าแรกน้อยกว่าค่าที่สองเป็นศูนย์หากมีค่าเท่ากันและเป็นค่าบวกหากค่าแรกมากกว่า

ดังนั้นถ้าฉันเข้าใจตัวอย่างที่คุณให้ถูกต้องคุณสามารถทำสิ่งที่ชอบ:

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
ฉันชอบคำตอบนี้ถ้า "รหัส" ในsortingArrจะไม่ซ้ำกัน - ซึ่งโชคดีที่พวกเขาอยู่ในกรณีของฉัน :)
dillondrenzek

3
คุณควรประกาศsortingArrayด้านนอกของฟังก์ชั่นเพื่อหลีกเลี่ยงการประกาศซ้ำในแต่ละการเรียงลำดับ
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

ฉันเดาว่าคนส่วนใหญ่มาที่นี่เพื่อมองหาเทียบเท่ากับ array_multisort ของ PHP (ฉันทำ) ดังนั้นฉันคิดว่าฉันโพสต์คำตอบนั้นด้วย มีตัวเลือกสองสามอย่าง:

1. มีการใช้ JS ของ array_multisort ()อยู่แล้ว ขอบคุณ @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
ทางออกที่ยอดเยี่ยมหรือคุณสามารถใช้ _.index โดยและลบกะถ้าโครงสร้างข้อมูลของคุณซับซ้อนขึ้นเล็กน้อย
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 เป็น Array of Objects เช่น: {1: {…}, 2: {…}, 3: {…}, 4: {…}, 5: {…}} แต่ arrayWithReferenceOrder เป็นเพียงอาร์เรย์ปกติหรือไม่
คริสตัล

3
@sushruth วิธีนี้จัดเรียงอาร์เรย์ได้อย่างไร
hitautodestruct

@ คริสตัลนั่นคือวัตถุไม่ใช่อาร์เรย์ของวัตถุ องค์ประกอบ / รายการในวัตถุไม่มีคำสั่งนั่นคือไม่ได้ตั้งค่าลำดับของพวกเขา [{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
นี่เป็นคำตอบที่สะอาดที่สุดและควรได้รับคำตอบ ขอบคุณ!
นิวแมน

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
โปรดพิจารณาการเพิ่มคำอธิบายสั้น ๆ / คำอธิบายอธิบายสาเหตุ / วิธีที่รหัสนี้ตอบคำถาม
นิส

3

นี่คือสิ่งที่ฉันกำลังมองหาและฉันได้ทำการเรียง Array of Array จาก Array อื่น:

มันเป็น ^ 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

ฉันต้องทำสิ่งนี้เพื่อเพย์โหลด JSON ที่ฉันได้รับจาก API แต่มันไม่ได้อยู่ในลำดับที่ฉันต้องการ

Array ให้เป็นอาร์เรย์อ้างอิงซึ่งเป็นอาร์เรย์ที่คุณต้องการให้เรียงลำดับที่สองโดย:

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

ในกรณีที่คุณต้องมาที่นี่เพื่อทำสิ่งต่าง ๆ กับวัตถุนี่คือการปรับคำตอบที่ยอดเยี่ยมของ @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

ใช้วิธีการ $ .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]);
}

-1

ใช้จุดตัดของสองอาร์เรย์

Ex:

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.