Iterasi di atas array asosiatif Javascript dalam urutan yang diurutkan

109

Katakanlah saya memiliki array asosiatif Javascript (alias hash, alias kamus):

var a = new Array();
a['b'] = 1;
a['z'] = 1;
a['a'] = 1;

Bagaimana cara saya mengulang kunci dalam urutan yang diurutkan? Jika itu membantu menyederhanakan banyak hal, saya bahkan tidak membutuhkan nilainya (semuanya hanya angka 1).

mike
sumber
11
mengapa Anda menggunakan konstruksi Array () baru dan kemudian menggunakannya seperti objek?
Luke Schafer
@ Luke .. Saya melakukan ini pada awalnya juga, berasal dari latar belakang PHP. Saya telah belajar sekarang :)
alex
20
@ Luke: karena saya tidak berpengalaman, sepertinya. Bisakah Anda memposting jawaban yang benar?
mike
4
Anda dapat membuat objek apa saja. Dalam Javascript tidak ada perbedaan antara kamus / "larik bernama" dan objek biasa. Oleh karena itu, Anda dapat mengakses a ['b'] dengan ab dan sebaliknya. Cara terpendek untuk membuat objek adalah a = {};.
Lodewijk

Jawaban:

124

Anda tidak dapat mengulanginya secara langsung, tetapi Anda dapat menemukan semua kuncinya dan kemudian menyortirnya.

var a = new Array();
a['b'] = 1;
a['z'] = 1;
a['a'] = 1;    

function keys(obj)
{
    var keys = [];

    for(var key in obj)
    {
        if(obj.hasOwnProperty(key))
        {
            keys.push(key);
        }
    }

    return keys;
}

keys(a).sort(); // ["a", "b", "z"]

Namun, variabel 'a' tidak perlu dibuat menjadi array. Anda benar-benar hanya menggunakannya sebagai objek dan harus membuatnya seperti ini:

var a = {};
a["key"] = "value";
Matthew
sumber
28
Anda harus selalu memeriksa forloop jika obj.hasOwnProperty(key).
viam0Zah
3
@Lalit - jika Anda mengacu pada komentar Torok, itu karena Anda tidak memiliki apa pun yang mengganggu prototipe objek, yang tidak dapat Anda andalkan.
Luke Schafer
1
+1 ke Torok. Alangkah baiknya jika jawabannya menyertakan hasOwnProperty ().
Jon Onstott
136

Anda dapat menggunakan metode bawaan Object.keys :

var sorted_keys = Object.keys(a).sort()

(Catatan: ini tidak berfungsi di browser yang sangat lama yang tidak mendukung EcmaScript5, terutama IE6, 7 dan 8. Untuk detail statistik terkini, lihat tabel ini )

molnarg
sumber
@ michael667 Mungkin karena IE 7 dan 8 masih banyak digunakan (sayangnya, terima kasih MS)
Alexander Reifinger
1
Untungnya, IE7 berada di 0,5% dan IE8 berada di 8% saat ini.
molnarg
3
if (!Object.keys) { Object.keys = function (obj) { var op, result = []; for (op in obj) { if (obj.hasOwnProperty(op) { result.push(op) } } return result }
Jordan Reiter
Saya suka yang ini, terima kasih. inilah kode saya memanfaatkan ini, $ (Object.keys (list)). map (function (i, e) {return n + '=' + list [n];}). get (). join ('&'); // concat untuk url querystring
Elaine
1
Pembaruan 2016: Ini mungkin jawaban yang diterima
rinogo
14

Anda bahkan dapat membuat prototipe ke objek:

Object.prototype.iterateSorted = function(worker)
{
    var keys = [];
    for (var key in this)
    {
        if (this.hasOwnProperty(key))
            keys.push(key);
    }
    keys.sort();

    for (var i = 0; i < keys.length; i++)
    {
        worker(this[ keys[i] ]);
    }
}

dan penggunaan:

var myObj = { a:1, b:2 };
myObj.iterateSorted(function(value)
{
    alert(value);
} 
Luke Schafer
sumber
3
Saya memberi suara positif untuk jawaban ini, sepertinya cukup bagus, tetapi ternyata itu merusak jquery :( stackoverflow.com/questions/1827458/… dan secara umum dianggap sebagai ide yang sangat buruk "Anda tidak boleh memperluas Object.prototype. Ini lebih dari sekadar merusak jQuery; itu benar-benar merusak fitur "object-as-hashtables" dari Javascript. Jangan lakukan itu. Anda dapat bertanya kepada John Resig, dan dia akan memberi tahu Anda hal yang sama. "
msanjay
Kamu tahu apa? Saya juga benci prototipe :) Saya tidak pernah menggunakannya dan secara aktif melarang penggunaannya. Saya merasa seperti ini 3,5 tahun yang lalu ketika saya menulis jawaban ini, tetapi tetap menyarankannya ... terima kasih telah memberikan infonya. Sebagai tambahan, itu TIDAK HARUS merusak kerangka kerja karena mereka harus SELALU menggunakan hasOwnProperty saat mengiterasi objek
Luke Schafer
Berikut adalah contoh menggunakan nilai alih-alih kunci mereka untuk menyortir sambil tetap mempertahankan key -> valuehubungan.
Xeoncross
6

Saya setuju dengan jawaban Swingley , dan saya pikir ini adalah poin penting karena banyak solusi yang lebih rumit ini hilang. Jika Anda hanya mementingkan kunci dalam array asosiatif dan semua nilainya adalah '1', maka cukup simpan 'keys' sebagai nilai dalam array.

Dari pada:

var a = { b:1, z:1, a:1 };
// relatively elaborate code to retrieve the keys and sort them

Menggunakan:

var a = [ 'b', 'z', 'a' ];
alert(a.sort());

Satu kekurangannya adalah Anda tidak dapat menentukan apakah kunci tertentu disetel dengan mudah. Lihat jawaban ini untuk fungsi javascript inarray jawaban untuk masalah itu. Satu masalah dengan solusi yang disajikan adalah itu a.hasValue('key')akan menjadi sedikit lebih lambat dari a['key']. Itu mungkin atau mungkin tidak penting dalam kode Anda.

Berikan Wagner
sumber
3

Tidak ada cara ringkas untuk secara langsung memanipulasi "kunci" dari objek Javascript. Ini tidak benar-benar dirancang untuk itu. Apakah Anda memiliki kebebasan untuk menempatkan data Anda di sesuatu yang lebih baik daripada objek biasa (atau Array, seperti yang disarankan kode sampel Anda)?

Jika demikian, dan jika pertanyaan Anda dapat dirumuskan ulang sebagai "Objek seperti kamus apa yang harus saya gunakan jika saya ingin mengulangi kunci dalam urutan yang diurutkan?" maka Anda bisa mengembangkan objek seperti ini:

var a = {
  keys : new Array(),
  hash : new Object(),
  set : function(key, value) {
    if (typeof(this.hash[key]) == "undefined") { this.keys.push(key); }
    this.hash[key] = value;
  },
  get : function(key) {
    return this.hash[key];
  },
  getSortedKeys : function() {
    this.keys.sort();
    return this.keys;
  }
};

// sample use
a.set('b',1);
a.set('z',1);
a.set('a',1);
var sortedKeys = a.getSortedKeys();
for (var i in sortedKeys) { print(sortedKeys[i]); }

Jika Anda tidak memiliki kendali atas fakta bahwa data berada dalam objek biasa, utilitas ini akan mengonversi objek reguler ke kamus yang berfungsi penuh:

a.importObject = function(object) {
  for (var i in object) { this.set(i, object); }
};

Ini adalah definisi objek (bukan fungsi konstruktor yang dapat digunakan kembali) untuk kesederhanaan; edit sesuka hati.

Travis Wilson
sumber
2

Dapatkan kunci di forloop pertama , urutkan, gunakan hasil yang diurutkan di forloop ke-2 .

var a = new Array();
a['b'] = 1;
a['z'] = 1;
a['a'] = 1;

var b = [];
for (k in a) b.push(k);
b.sort();
for (var i = 0; i < b.length; ++i) alert(b[i]);
poin
sumber
2

Anda dapat menggunakan keysfungsi dari pustaka underscore.js untuk mendapatkan kunci, lalu sort()metode array untuk mengurutkannya:

var sortedKeys = _.keys(dict).sort();

The keysfungsi dalam kode sumber garis bawah ini:

// Retrieve the names of an object's properties.
// Delegates to **ECMAScript 5**'s native `Object.keys`
_.keys = nativeKeys || function(obj) {
    if (obj !== Object(obj)) throw new TypeError('Invalid object');
    var keys = [];
    for (var key in obj) if (_.has(obj, key)) keys.push(key);
    return keys;
};    

// Shortcut function for checking if an object has a given property directly
// on itself (in other words, not on a prototype).
_.has = function(obj, key) {
    return hasOwnProperty.call(obj, key);
};
Eugene Yarmash
sumber
0
<script type="text/javascript">
    var a = {
        b:1,
        z:1,
        a:1
    }; // your JS Object
    var keys = [];
    for (key in a) {
        keys.push(key);
    }
    keys.sort();
    var i = 0;
    var keyslen = keys.length;
    var str = '';
    //SORTED KEY ITERATION
    while (i < keyslen) {
        str += keys[i] + '=>' + a[keys[i]] + '\n';
        ++i;
    }
    alert(str);
    /*RESULT:
    a=>1
    b=>1
    z=>1
    */
</script>
Fran Corpier
sumber
0

var a = new Array();
a['b'] = 1;
a['z'] = 1;
a['a'] = 1;


var keys=Object.keys(a).sort();
for(var i=0,key=keys[0];i<keys.length;key=keys[++i]){
  document.write(key+' : '+a[key]+'<br>');
}

Vlad V
sumber
0

Saya sangat suka ide prototipe @ luke-schafer, tetapi juga mendengar apa yang dia katakan tentang masalah dengan prototipe. Bagaimana dengan menggunakan fungsi sederhana?

function sortKeysAndDo( obj, worker ) {
  var keys = Object.keys(obj);
  keys.sort();
  for (var i = 0; i < keys.length; i++) {
     worker(keys[i], obj[keys[i]]);
  }
}

function show( key, value ) {
  document.write( key + ' : ' + value +'<br>' );
}

var a = new Array();
a['b'] = 1;
a['z'] = 1;
a['a'] = 1;

sortKeysAndDo( a, show);

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

sortKeysAndDo( my_object, show);

Ini tampaknya menghilangkan masalah dengan prototipe dan masih menyediakan iterator yang diurutkan untuk objek. Saya sebenarnya bukan ahli JavaScript, jadi saya ingin tahu apakah solusi ini menyembunyikan kekurangan yang saya lewatkan.

EFC
sumber