我有关联数组:
array["sub2"] = 1;
array["sub0"] = -1;
array["sub1"] = 0;
array["sub3"] = 1;
array["sub4"] = 0;
按其值排序(降序)的最优雅方法是什么,结果将是一个按以下顺序具有相应索引的数组:
sub2, sub3, sub1, sub4, sub0
我有关联数组:
array["sub2"] = 1;
array["sub0"] = -1;
array["sub1"] = 0;
array["sub3"] = 1;
array["sub4"] = 0;
按其值排序(降序)的最优雅方法是什么,结果将是一个按以下顺序具有相应索引的数组:
sub2, sub3, sub1, sub4, sub0
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 = 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]});
}
您转储到一个对象(如您的对象)中并获得一个键数组 - eh 属性 - 返回,按 eh 对象的(数值)值降序排序。
这仅在您的值是数字时才有效。Tweek the little function(a,b)
in there 改变排序机制以升序工作,或为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;
});
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;
}
然后你会用一个比较器函数调用它。
在我看来,针对此处特定情况的最佳方法是建议的一种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]]
}
除此之外,我在这里提供了一个更“通用”的函数,您甚至可以在更广泛的情况下使用它进行排序,并且将我刚刚建议的改进与Ben Blank(对字符串值进行排序)和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 的一些有用参考