У меня ассоциативный массив:
array["sub2"] = 1;
array["sub0"] = -1;
array["sub1"] = 0;
array["sub3"] = 1;
array["sub4"] = 0;
Каков наиболее элегантный способ сортировки (по убыванию) по его значениям, когда результатом будет массив с соответствующими индексами в следующем порядке:
sub2, sub3, sub1, sub4, sub0
javascript
arrays
sorting
associative
Джон Смит
источник
источник
Ответы:
В Javascript нет «ассоциативных массивов», как вы о них думаете. Вместо этого у вас просто есть возможность устанавливать свойства объекта с использованием синтаксиса, подобного массиву (как в вашем примере), а также возможность перебирать свойства объекта.
Результатом этого является то, что нет никакой гарантии относительно порядка, в котором вы перебираете свойства, поэтому для них нет ничего лучше сортировки. Вместо этого вам нужно преобразовать свойства вашего объекта в «истинный» массив (который гарантирует порядок). Вот фрагмент кода для преобразования объекта в массив из двух кортежей (двухэлементные массивы), сортировки его, как вы описываете, а затем итерации по нему:
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 = keys = Object.keys(obj); return keys.sort(function(a,b){return obj[b]-obj[a]}); }
для действительно старых браузеров используйте вместо этого:
function getSortedKeys(obj) { var keys = []; for(var key in obj) keys.push(key); return keys.sort(function(a,b){return obj[b]-obj[a]}); }
Вы сбрасываете объект (например, ваш) и получаете массив ключей - а, свойства - обратно, отсортированных по убыванию (числового) значения, э-э, значений объекта, э-э.
Это работает, только если ваши значения числовые. Немного подправьте,
function(a,b)
чтобы изменить механизм сортировки для работы по возрастанию или работы дляstring
значений (например). Оставил в качестве упражнения для читателя.источник
Продолжение обсуждения и других решений, описанных в разделе Как отсортировать (ассоциативный) массив по значению? с лучшим решением (для моего случая) от 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; });
источник
sort()
обрабатываются по-разному. Это сбивало меня с толку в течение часа, пока я не нашел этот пример stackoverflow.com/questions/6712034/…a.name.toLowerCase() > b.name.toLowerCase()
На самом деле в 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; }
источник
var stuff = {"a":1 , "b":3 , "c":0 } sortMapByValue(stuff) [Array[2], Array[2], Array[2]]
Я использую $ .each из 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);
источник
На мой взгляд, лучший подход для конкретного случая здесь - это предложенный общий пик . Небольшое улучшение, которое я предлагаю, работает в современных браузерах:
// 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]] }
И последнее, но не менее важное: несколько полезных ссылок на Object.keys и Array.sort.
источник
Просто так, что кто-то ищет сортировки на основе кортежей. Это сравнит первый элемент объекта в массиве, чем второй элемент и так далее. т.е. в приведенном ниже примере он будет сравниваться сначала по «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))
ВЫХОДЫ
[ { 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 "правильный", но, продолжая комментировать ...
Да ..
Object.keys()
это намного лучше .Но что еще лучше ? Да вот оно
coffeescript
!sortedKeys = (x) -> Object.keys(x).sort (a,b) -> x[a] - x[b] sortedKeys 'a' : 1 'b' : 3 'c' : 4 'd' : -1
источник