私は連想配列を持っています:
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には、あなたが考えているような「連想配列」がありません。代わりに、(例のように)配列のような構文を使用してオブジェクトのプロパティを設定する機能に加えて、オブジェクトのプロパティを反復処理する機能があります。
その結果、プロパティを反復処理する順序が保証されないため、プロパティの種類に勝るものはありません。代わりに、オブジェクトのプロパティを「真の」配列に変換する必要があります(これは順序を保証します)。オブジェクトを2タプルの配列(2要素配列)に変換し、説明どおりに並べ替えてから、反復処理するためのコードスニペットを次に示します。
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]});
}
オブジェクト(あなたのような)をダンプし、キーの配列(ehプロパティ)を取得し、、 eh、オブジェクトの(数値)値の降順でソートします。
これは、値が数値の場合にのみ機能します。そこに少し時間を入れて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/…の 例を見つけるまで、1時間混乱しました。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]]
私はjqueryの$ .eachを使用しますが、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]]
}
これに加えて、より広い範囲の状況でも並べ替えに使用できる、より「一般的な」関数をここに提供します。これは、先ほど提案した改善と、Ben Blank(文字列値も並べ替える)およびPopeJohnPaulII(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へのいくつかの有用な参照
ちょうどそれがそこにあり、誰かがタプルベースの種類を探しています。これにより、配列内のオブジェクトの最初の要素が2番目の要素よりも比較されます。つまり、以下の例では、最初に「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 } ]