2015-04-17 64 views
9
陣列由另一個內容

說我有Person對象的數組:排序在JavaScript

var people = [{name: "Joe Schmo", age: 36}, {name: "JANE DOE", age: 40}]; 

和我有可以排序字符串箱子的陣列不區分大小寫的函數:

function caseInsensitiveSort(arr) { ... } 

是否有任何直接的方法來結合我現有的排序功能Array.prototype.map排序people陣列只使用name鍵?

I.e.它會產生

var people = [{name: "JANE DOE", age: 40}, {name: "Joe Schmo", age: 36}]; 

做手工也不是很難在這種特殊情況下,

people.sort(function (a, b) { 
    return a.name.localeCompare(b.name); 
}); 

,但我想不出這樣做的一種方式,讓我用預現有的排序功能。在排序功能更加定製的情況下,這將是有用的。

編輯:我相信這裏的核心問題是要做到這一點,你需要能夠弄清楚當你對代理數組進行排序時,原始索引被映射到了什麼位置。在一般情況下,使用JS的本地sort函數獲得這些新索引似乎不可能。但我很樂意被證明是錯誤的。

編輯:我試圖做到這一點的方式效率太低,無法使用。請參閱下面的答案,使用比較函數替代解決方案。

+0

如果'caseInsensitiveSort'接受一個數組,你需要在名稱的數組給該函數的名稱進行排序,然後基於與名稱陣列上的對象數組排序。聽起來像是一種非常複雜的方式來做簡單的事情。 – adeneo

+0

它會處理幾個元素嗎?因爲'Array.prototype.map'方法創建一個新數組,所以對於數百萬條記錄來說,最好的選擇就是對它進行就地排序。 –

+0

@adeneo @Jordan你們倆都是對的。正如xdazz在下面指出的,正確的方法是將我的比較邏輯抽象爲一個單獨的函數,並將其提供給'Array.prototype.sort',而不是試圖將我的排序函數放入。 –

回答

4

你可以使用你現有的功能得到排序名稱數組,然後通過索引排序的名字排列在比較people數組進行排序。

var names = caseInsensitiveSort(people.map(function(person) { 
    return person.name; 
})); 

people.sort(function (a, b) { 
    return names.indexOf(a.name) - names.indexOf(b.name); 
}); 

但是,這是沒有效率的,你應該嘗試抽象出比較邏輯從caseInsensitiveSort功能爲caseInsensitiveCompare功能。

然後你的榜樣將成爲:

people.sort(function (a, b) { 
    return caseInsensitiveCompare(a.name, b.name); 
}); 
+0

每次迭代使用'indexOf'兩次會使這個數組變得相當緩慢,但這可能是以一般方式完成它的唯一可能方式。 +1。 –

+1

@ChrisMiddleton你不能從'caseInsensitiveSort'函數中抽象比較邏輯嗎? – xdazz

+0

是的,你是對的。這是我想的真正答案。要以通用和有效的方式完成此操作,您需要在比較函數級別工作,而不是排序函數。謝謝。 –

1

根據您的caseInsensitiveSort()功能是如何工作的,你可以利用一個.toString()的方法來做到這一點:

var toSort = people.map(function (person) { 
    return { 
     person: person, 
     toString: function() { 
      return person.name; 
     } 
    }; 
}); 

caseInsensitiveSort(toSort); 

people = toSort.map(function (item) { return item.person; }); 

如果這不是一個選項,一個混亂但仍然有效的方法是再排序基於這些名稱進行排序,它們映射到自己的索引和:

var names = people.map(function (person) { return person.name; }); 

caseInsensitiveSort(names); 

var nameMap = {}; 
names.forEach(function (name, i) { 
    nameMap[name] = i; 
}); 

people.sort(function (a, b) { 
    return nameMap[a.name] - nameMap[b.name]; 
}); 
+0

感謝您的補充 - 您的第二個解決方案與我在詢問時的想法類似。它當然只適用於你正在排序的值是可關鍵值的情況,但這可能是一個不可避免的限制,除非你使用散列值作爲非可鍵值。 –

+0

@ChrisMiddleton是的,這當然是對的。它適用於名稱,但不適用於所有類型的值。 – JLRishe