Как сортировать ассоциативный массив по его значениям в Javascript?
у меня есть ассоциативный массив:
array["sub2"] = 1;
array["sub0"] = -1;
array["sub1"] = 0;
array["sub3"] = 1;
array["sub4"] = 0;
каков самый элегантный способ сортировки (по убыванию) по его значениям, где результатом будет массив с соответствующими индексами в этом порядке:
sub2, sub3, sub1, sub4, sub0?
10 ответов
Javascript не имеет "ассоциативных массивов", как вы о них думаете. Вместо этого у вас просто есть возможность установить свойства объекта с помощью синтаксиса типа массива (как в вашем примере), а также возможность перебирать свойства объекта.
в результате этого нет никакой гарантии относительно ордер в котором вы перебираете свойства, поэтому для них нет ничего похожего на сортировку. Вместо этого вам нужно будет преобразовать свойства объекта в a массив" true " (который гарантирует порядок). Вот фрагмент кода для преобразования объекта в массив из двух кортежей (двухэлементных массивов), сортировки его, как вы описываете, а затем итерации по нему:
var tuples = [];
for (var key in obj) tuples.push([key, obj[key]]);
tuples.sort(function(a, b) {
a = a[1];
b = b[1];
return a < b ? -1 : (a > b ? 1 : 0);
});
for (var i = 0; i < tuples.length; i++) {
var key = tuples[i][0];
var value = tuples[i][1];
// do something with key and value
}
вы можете найти более естественным обернуть это в функцию, которая принимает обратный вызов:
function bySortedValue(obj, callback, context) {
var tuples = [];
for (var key in obj) tuples.push([key, obj[key]]);
tuples.sort(function(a, b) {
return a[1] < b[1] ? 1 : a[1] > b[1] ? -1 : 0
});
var length = tuples.length;
while (length--) callback.call(context, tuples[length][0], tuples[length][1]);
}
bySortedValue({
foo: 1,
bar: 7,
baz: 3
}, function(key, value) {
document.getElementById('res').innerHTML += `${key}: ${value}<br>`
});
<p id='res'>Result:<br/><br/><p>
вместо того, чтобы исправлять вас по семантике "ассоциативного массива", я думаю, что это то, что вы хотите:
function getSortedKeys(obj) {
var keys = []; for(var key in obj) keys.push(key);
return keys.sort(function(a,b){return obj[b]-obj[a]});
}
вы сбрасываете объект (например, ваш) и получаете массив ключей - EH properties - back, отсортированных по убыванию (числового) значения, eh, значения, eh, объекта.
это работает только если значения являются числовыми. Tweek маленький function(a,b)
там, чтобы изменить механизм сортировки на работу по возрастанию или работу для string
значения (для образец.) Оставлено как упражнение для читателя.
EDIT: люди продолжают голосовать за этот ответ, но он действительно старый. Пожалуйста пересмотрите, почему вы не просто используете
продолжение обсуждения и другие решения, рассмотренные в как отсортировать (ассоциативный) массив по значению? С лучшим решением (для моего случая), являющимся на основе SAML (цитируется ниже).
массивы могут иметь только числовые индексы. Вам нужно будет переписать это как объект или массив объектов.
var status = new Array();
status.push({name: 'BOB', val: 10});
status.push({name: 'TOM', val: 3});
status.push({name: 'ROB', val: 22});
status.push({name: 'JON', val: 7});
Если вам нравится status.push
метод, вы можете отсортировать его с:
status.sort(function(a,b) {
return a.val - b.val;
});
в JavaScript действительно нет такой вещи, как "ассоциативный массив". Что у вас есть только простой старый объект. Они работают как ассоциативные массивы, конечно, и ключи доступны, но нет семантики вокруг порядка ключей.
вы можете превратить свой объект в массив объектов (пары ключ / значение) и отсортировать это:
function sortObj(object, sortFunc) {
var rv = [];
for (var k in object) {
if (object.hasOwnProperty(k)) rv.push({key: k, value: object[k]});
}
rv.sort(function(o1, o2) {
return sortFunc(o1.key, o2.key);
});
return rv;
}
тогда вы бы назвали это функцией компаратора.
вот вариант ответа Бена бланка, если вам не нравятся кортежи.
это экономит вам несколько символов.
var keys = [];
for (var key in sortme) {
keys.push(key);
}
keys.sort(function(k0, k1) {
var a = sortme[k0];
var b = sortme[k1];
return a < b ? -1 : (a > b ? 1 : 0);
});
for (var i = 0; i < keys.length; ++i) {
var key = keys[i];
var value = sortme[key];
// Do something with key and value.
}
никаких ненужных осложнений не требуется...
function sortMapByValue(map)
{
var tupleArray = [];
for (var key in map) tupleArray.push([key, map[key]]);
tupleArray.sort(function (a, b) { return a[1] - b[1] });
return tupleArray;
}
Я использую $.каждый в jQuery, но вы можете сделать это с помощью цикла for, улучшение это:
//.ArraySort(array)
/* Sort an array
*/
ArraySort = function(array, sortFunc){
var tmp = [];
var aSorted=[];
var oSorted={};
for (var k in array) {
if (array.hasOwnProperty(k))
tmp.push({key: k, value: array[k]});
}
tmp.sort(function(o1, o2) {
return sortFunc(o1.value, o2.value);
});
if(Object.prototype.toString.call(array) === '[object Array]'){
$.each(tmp, function(index, value){
aSorted.push(value.value);
});
return aSorted;
}
if(Object.prototype.toString.call(array) === '[object Object]'){
$.each(tmp, function(index, value){
oSorted[value.key]=value.value;
});
return oSorted;
}
};
Так что теперь вы можете сделать
console.log("ArraySort");
var arr1 = [4,3,6,1,2,8,5,9,9];
var arr2 = {'a':4, 'b':3, 'c':6, 'd':1, 'e':2, 'f':8, 'g':5, 'h':9};
var arr3 = {a: 'green', b: 'brown', c: 'blue', d: 'red'};
var result1 = ArraySort(arr1, function(a,b){return a-b});
var result2 = ArraySort(arr2, function(a,b){return a-b});
var result3 = ArraySort(arr3, function(a,b){return a>b});
console.log(result1);
console.log(result2);
console.log(result3);
просто так это там, и кто-то ищет Кортеж на основе сортов. Это позволит сравнить первый элемент объекта в массиве, чем второй элемент и так далее. Я. e в приведенном ниже примере он будет сравнивать сначала "a", затем" b " и так далее.
let arr = [
{a:1, b:2, c:3},
{a:3, b:5, c:1},
{a:2, b:3, c:9},
{a:2, b:5, c:9},
{a:2, b:3, c:10}
]
function getSortedScore(obj) {
var keys = [];
for(var key in obj[0]) keys.push(key);
return obj.sort(function(a,b){
for (var i in keys) {
let k = keys[i];
if (a[k]-b[k] > 0) return -1;
else if (a[k]-b[k] < 0) return 1;
else continue;
};
});
}
console.log(getSortedScore(arr))
OUPUTS
[ { a: 3, b: 5, c: 1 },
{ a: 2, b: 5, c: 9 },
{ a: 2, b: 3, c: 10 },
{ a: 2, b: 3, c: 9 },
{ a: 1, b: 2, c: 3 } ]
лучшим подходом для конкретного случая здесь, на мой взгляд, является один commonpike предложил. Небольшое улучшение я бы предложил, что работает в современных браузерах:
// aao is the "associative array" you need to "sort"
Object.keys(aao).sort(function(a,b){return aao[b]-aao[a]});
Это может быть легко наносится и отлично работать в конкретном случае здесь, так что вы можете сделать:
let aoo={};
aao["sub2"]=1;
aao["sub0"]=-1;
aao["sub1"]=0;
aao["sub3"]=1;
aao["sub4"]=0;
let sk=Object.keys(aao).sort(function(a,b){return aao[b]-aao[a]});
// now you can loop using the sorted keys in `sk` to do stuffs
for (let i=sk.length-1;i>=0;--i){
// do something with sk[i] or aoo[sk[i]]
}
кроме того, я предоставляю здесь более "общую" функцию, которую вы можете использовать для сортировки даже в более широком диапазоне ситуаций, и это смешивает улучшение, которое я только что предложил с подходы ответов по Бен Пустой (сортировки строковых значений) и PopeJohnPaulII (сортировка по конкретному полю/свойству объекта) и позволяет вам решить, хотите ли вы восходящий или нисходящий порядок, вот он:
// aao := is the "associative array" you need to "sort"
// comp := is the "field" you want to compare or "" if you have no "fields" and simply need to compare values
// intVal := must be false if you need comparing non-integer values
// desc := set to true will sort keys in descendant order (default sort order is ascendant)
function sortedKeys(aao,comp="",intVal=false,desc=false){
let keys=Object.keys(aao);
if (comp!="") {
if (intVal) {
if (desc) return keys.sort(function(a,b){return aao[b][comp]-aao[a][comp]});
else return keys.sort(function(a,b){return aao[a][comp]-aao[a][comp]});
} else {
if (desc) return keys.sort(function(a,b){return aao[b][comp]<aao[a][comp]?1:aao[b][comp]>aao[a][comp]?-1:0});
else return keys.sort(function(a,b){return aao[a][comp]<aao[b][comp]?1:aao[a][comp]>aao[b][comp]?-1:0});
}
} else {
if (intVal) {
if (desc) return keys.sort(function(a,b){return aao[b]-aao[a]});
else return keys.sort(function(a,b){return aao[a]-aao[b]});
} else {
if (desc) return keys.sort(function(a,b){return aao[b]<aao[a]?1:aao[b]>aao[a]?-1:0});
else return keys.sort(function(a,b){return aao[a]<aao[b]?1:aao[a]>aao[b]?-1:0});
}
}
}
вы можете проверить функциональные возможности пробовать что-то вроде следующего кода:
let items={};
items['Edward']=21;
items['Sharpe']=37;
items['And']=45;
items['The']=-12;
items['Magnetic']=13;
items['Zeros']=37;
//equivalent to:
//let items={"Edward": 21, "Sharpe": 37, "And": 45, "The": -12, ...};
console.log("1: "+sortedKeys(items));
console.log("2: "+sortedKeys(items,"",false,true));
console.log("3: "+sortedKeys(items,"",true,false));
console.log("4: "+sortedKeys(items,"",true,true));
/* OUTPUT
1: And,Sharpe,Zeros,Edward,Magnetic,The
2: The,Magnetic,Edward,Sharpe,Zeros,And
3: The,Magnetic,Edward,Sharpe,Zeros,And
4: And,Sharpe,Zeros,Edward,Magnetic,The
*/
items={};
items['k1']={name:'Edward',value:21};
items['k2']={name:'Sharpe',value:37};
items['k3']={name:'And',value:45};
items['k4']={name:'The',value:-12};
items['k5']={name:'Magnetic',value:13};
items['k6']={name:'Zeros',value:37};
console.log("1: "+sortedKeys(items,"name"));
console.log("2: "+sortedKeys(items,"name",false,true));
/* OUTPUT
1: k6,k4,k2,k5,k1,k3
2: k3,k1,k5,k2,k4,k6
*/
как я уже сказал, Вы можете перебирать отсортированные ключи, если вам нужно делать вещи
let sk=sortedKeys(aoo);
// now you can loop using the sorted keys in `sk` to do stuffs
for (let i=sk.length-1;i>=0;--i){
// do something with sk[i] or aoo[sk[i]]
}
последнее, но не менее, некоторые полезные ссылки и массив.вроде
@commonpike ответ "правильный", но, как он продолжает комментировать...
большинство браузеров в настоящее время просто поддерживают
Object.keys()
да.. Object.keys()
is лучше.
но еще лучше? Да, это в coffeescript
!
sortedKeys = (x) -> Object.keys(x).sort (a,b) -> x[a] - x[b]
sortedKeys
'a' : 1
'b' : 3
'c' : 4
'd' : -1
[ 'd', 'a', 'b', 'c' ]