web-dev-qa-db-ja.com

Javascriptオブジェクトを並べ替える、または配列に変換する方法は?

サーバーから取得したJSONデータがいくつかあります。私のJavaScriptでは、いくつかの並べ替えを行います。 sort()関数は私が望むことをするだろうと思います。

ただし、JavaScriptはJSONデータをすぐにオブジェクトに変換しているようです。 sort()メソッドを使用しようとすると、エラーが大量に発生します(テストにFirebugを使用)。

私はネットを見回しましたが、誰もが1つには、JSONオブジェクトはすでにJavaScript配列であり、オブジェクトは配列のように扱うことができると言っているようです。 この質問 のように、答えの1つで、「[オブジェクトオブジェクト]はあなたのデータです。配列と同じようにアクセスできます」と言います。

しかし、それは正確には真実ではありません。 JavaScriptでは、オブジェクトでsort()を使用できません。そして、デフォルトの仮定はそれらがすべて同じであるということなので、オブジェクトを配列に変換する方法、JavaScriptにそれを1つとして扱うように強制する方法、またはそのような方法についての説明はどこにもありません。

だから...このデータを配列として扱い、sort()するためにJavaScriptを取得するにはどうすればよいですか?

オブジェクトのコンソールログ出力は次のようになります(「レベル」の値でソートできるようにしたい)。

オブジェクトJSONdata

{ 
1: {
    displayName: "Dude1",
    email: "[email protected]<mailto:[email protected]>",
    lastActive: 1296980700, 
    level: 57, 
    timeout: 12969932837
}, 2: {
    displayName: "Dude2",
    email: "[email protected]<mailto:[email protected]>",
    lastActive: 1296983456,
    level: 28,
    timeout: 12969937382
}, 3: {
    displayName: "Dude3",
    email: "[email protected]<mailto:[email protected]>",
    lastActive: 1296980749,
    level: 99,
    timeout: 129699323459
} 
}
37
Questioner

Array.prototype.slice.call(arrayLikeObject)

は、配列のようなオブジェクトを配列に変換する標準的な方法です。

これはargumentsオブジェクトに対してのみ実際に機能します。汎用オブジェクトを配列に変換するのは少し面倒です。 nderscore.js のソースは次のとおりです。

_.toArray = function(iterable) {
    if (!iterable)                return [];
    if (iterable.toArray)         return iterable.toArray();
    if (_.isArray(iterable))      return iterable;
    if (_.isArguments(iterable))  return slice.call(iterable);
    return _.values(iterable);
};

_.values = function(obj) {
    return _.map(obj, _.identity);
};

オブジェクトをループし、自分で配列にマッピングする必要があることがわかります。

var newArray = []
for (var key in object) {
    newArray.Push(key);
}

配列と「連想配列」の概念を混同しています。 JavaScriptでは、object["key"]形式のデータにアクセスできるため、オブジェクトは一種の連想配列のように機能します。オブジェクトは順序付けられていないリストであるため、実際の連想配列ではありません。

オブジェクトと配列は大きく異なります。

アンダースコアの使用例:

var sortedObject = _.sortBy(object, function(val, key, object) {
    // return an number to index it by. then it is sorted from smallest to largest number
    return val;
});

実例 を参照してください

42
Raynos

JavaScriptオブジェクトを次のように配列に変換できるはずです...

var obj = {
    '1': 'a',
    '2': 'b',
    '3': 'c'  
};

var arr = [];

for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
      arr.Push(obj[key]);  
    }
}

console.log(arr); // ["a", "b", "c"]

jsFiddleで参照

7
alex

JavaScriptオブジェクトが配列のようなオブジェクト、つまり有効な数値lengthプロパティを持つObjectインスタンスである場合、次のことができます。 callメソッドのおかげで、多くのnativeArrayメソッドを直接使用します。例えば:

// Sorts the given objet in-place as if it was an array
Array.prototype.sort.call(yourObject);

ソートするエントリの数がわかっている場合( JavaScriptでオブジェクトのキー/プロパティの数を効率的にカウントする方法? )、次のことができます。

yourObject.length = theNumberOfEntries;
Array.prototype.sort.call(yourObject);
// Optionally: delete yourObject.length;

これは、配列のように、「0」、「1」、「2」、...でインデックス付けされたプロパティのみをlength - 1を含めてソートすることに注意してください。オブジェクトの他のプロパティは並べ替えられません。

6
Luc125

これらの回答のほとんどは、問題を過度に複雑にするか、JQueryまたはアンダースコアを使用しますが、OPはそれらを要求しませんでした。

次のようにオブジェクトを配列に変換できます。

myArray= Object.keys(data).map(function(key) { return data[key] });

そして、結果を次のようにソートします。

myArray.sort(function(x, y) {return x.level - y.level});

Id/indexが必要な場合は、もう少し行う必要があります。

Object.keys(data).map(function(key) { 
  var obj = data[key];
  obj.index = key;
  return obj 
});
5
andyhasit

オブジェクトの配列をそのプロパティの1つでグループ化しようとしたときに、最近この問題に遭遇しました。その結果、1つのオブジェクトがソートできませんでした。

具体的には、年ごとにグループ化し、降順でソートしたいブログ投稿の配列です。私はアンダースコアのユーティリティを使用しました:

var grouped = _.groupBy(blogposts, function(post){
  var date = new Date(post.publication_date)
  return date.getFullYear()
})
//=> { 2010: [blogpost, blogpost,etc], 2011: [blogpost, etc] }

@Raynosが説明したように、並べ替える前に最初に何らかの配列を作成する必要がありました...

アンダースコア(1.4)には、オブジェクトの{key:value}を[key、value]の配列にマッピングするpairsという素敵な小さなユーティリティがあります。以下と同等:

var paired = _.map(grouped, function(val, key){
  return [key, val]
})
//=> [ [2010, [blogpost, blogpost, ...] ], [2011, [blogpost, blogpost, ...]]...]

そこから、各ペアの最初の用語で簡単にソートできます。

最終結果は次のとおりです。

var grouped = _.groupBy(result.resource, function(resource){
  var date = new Date(resource.pub_date)
  return date.getFullYear() //+ "." + (date.getMonth()+1)
})

var paired = _.pairs(grouped)

var sorted = _.sortBy(paired, function(pairs){
  return -parseInt(pairs[0])
})

return sorted;
// Giving me the expected result:
//=> [ [2013, [blogpost, blogpost, ...] ], [2012, [blogpost, blogpost, ...]]...]

より良い、よりパフォーマンスの高い方法があると確信していますが、Rubyからこのコードはすぐに理解できます。

2
charlysisto

jQueryは、配列またはオブジェクトの各要素を反復処理し、結果を新しい配列にマッピングするマップ関数を提供します。

JQuery 1.6より前では、$。map()は配列の走査のみをサポートしていました。

これを使用して、次のようにオブジェクトを配列に変換できます...

  myArray = $.map(myObject, function (el) {
    return el;
  });

しかし...コールバック関数がnullまたはundefinedを返す場合、その値はremoved配列から、ほとんどの場合これは便利ですが、myArrayにnull値が必要な場合は問題を引き起こす可能性があります。

jQueryはこのためのソリューションを提供します...単一の値を持つ配列として値を返します

myArrayWithNulls = jQuery.map(myObject, function (el) {
  return [el];
});

以下に、2つのアプローチを示すフィドルを示します。 http://jsfiddle.net/chim/nFyPE/

http://jsperf.com/object-to-array-jquery-2

1
chim

オブジェクトである可能性のあるプロパティを持つオブジェクトを多次元配列に再帰的に変換する小さな関数を作成しました。このコードは、forEachメソッドとtoArrayメソッドのアンダースコアまたはlodashに依存しています。

function deepToArray(obj) {
    var copy = [];


    var i = 0;
    if (obj.constructor == Object ||
        obj.constructor == Array) {

        _.forEach(obj, process);

    } else {

        copy = obj;

    }


    function process(current, index, collection) {

        var processed = null;
        if (current.constructor != Object &&
            current.constructor != Array) {
            processed = current;
        } else {
            processed = deepToArray(_.toArray(current));
        }

        copy.Push(processed);

    }

    return copy;
}

フィドルは次のとおりです。 http://jsfiddle.net/gGT2D/

注:これは、元は配列であったオブジェクトを配列に戻すために作成されたため、配列以外のインデックスキー値は失われます。

1
Isioma Nnodum