Sıralı sırayla bir Javascript ilişkilendirilebilir dizisi üzerinde yineleme


109

Diyelim ki bir Javascript ilişkisel dizim var (hash, aka dictionary):

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

Anahtarları sıralı bir şekilde nasıl yineleyebilirim? İşleri basitleştirmeye yardımcı oluyorsa, değerlere bile ihtiyacım yok (hepsi sadece 1 numara).


11
neden new Array () yapısını kullanıyorsunuz ve sonra onu bir nesne gibi kullanıyorsunuz?
Luke Schafer

@Luke .. Bunu ilk başta PHP altyapısından geldim. Şimdi öğrendim :)
alex

20
@Luke: 'çünkü deneyimsizim, öyle görünüyor. Bir cevapta doğru yolu gönderebilir misin?
mike

4
Herhangi bir nesneyi kolayca oluşturabilirsiniz. Javascript'te bir sözlük / "adlandırılmış dizi" ile normal bir nesne arasında hiçbir fark yoktur. Bu nedenle, a ['b'] ye ab ile erişebilir ve bunun tersi de geçerlidir. Bir nesne oluşturmanın en kısa yolu a = {};.
Lodewijk

Yanıtlar:


124

Doğrudan bunları yineleyemezsiniz, ancak tüm anahtarları bulabilir ve sonra bunları sıralayabilirsiniz.

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"]

Ancak, 'a' değişkenini bir dizi yapmaya gerek yoktur. Onu gerçekten sadece bir nesne olarak kullanıyorsunuz ve şu şekilde oluşturmalısınız:

var a = {};
a["key"] = "value";

28
Her zaman fordöngüyü kontrol etmelisiniz eğer obj.hasOwnProperty(key).
viam0Zah

3
@Lalit - Torok'un yorumuna atıfta bulunuyorsanız, bunun nedeni, güvenemeyeceğiniz nesnenin prototipine müdahale eden hiçbir şeyinizin olmamasıdır.
Luke Schafer

1
Torok'a +1. Cevabın hasOwnProperty () içermesi güzel olurdu.
Jon Onstott

136

Sen kullanabilirsiniz Object.keys yerleşik yöntemiyle:

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

(Not: Bu, EcmaScript5'i desteklemeyen çok eski tarayıcılarda, özellikle IE6, 7 ve 8'de çalışmaz. Ayrıntılı güncel istatistikler için bu tabloya bakın )


@ michael667 Muhtemelen IE 7 ve 8 hala yaygın olarak kullanıldığından (ne yazık ki, teşekkür ederim MS)
Alexander Reifinger

1
Neyse ki şu an itibariyle IE7% 0,5 ve IE8% 8 seviyesinde.
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 }
Ürdün Reiter

Bunu seviyorum, teşekkür ederim. işte bunu kullanan kodum, $ (Object.keys (list)). map (function (i, e) {return n + '=' + list [n];}). get (). join ('&'); // url sorgu dizesi için concat
Elaine

1
2016 güncellemesi: Bu muhtemelen kabul edilen cevap olmalı
rinogo

14

hatta nesnenin prototipini de yapabilirsiniz:

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] ]);
    }
}

ve kullanım:

var myObj = { a:1, b:2 };
myObj.iterateSorted(function(value)
{
    alert(value);
} 

3
Bu cevaba oy verdim, oldukça iyi görünüyordu, ancak jquery'yi bozduğu ortaya çıktı :( stackoverflow.com/questions/1827458/… ve genel olarak çok kötü bir fikir olarak görülüyor "Object.prototype'ı asla genişletmemelisiniz. break jQuery; Javascript'in "hashtables olarak nesne" özelliğini tamamen bozar. Yapmayın. John Resig'e sorabilirsiniz, o da size aynı şeyi söyleyecektir. "
msanjay

Biliyor musun? Prototiplerden de nefret ediyorum :) Onları hiç kullanmıyorum ve aktif olarak kullanılmasını engellemiyorum. 3,5 yıl önce bu cevabı yazdığımda böyle hissettim, ama yine de önerdim ... bilgiyi sağladığınız için teşekkürler. Bir kenara, nesneleri yinelerken HER ZAMAN hasOwnProperty kullanmaları gerektiği gibi çerçeveleri KIRMAMALIDIR
Luke Schafer

Burada, ilişkiyi korurken sıralama için anahtarlar yerine değerleri kullanan bir örnek verilmiştir key -> value.
Xeoncross

6

Swingley'in cevabına katılıyorum ve bu daha ayrıntılı çözümlerin çoğunun eksik olmasının önemli bir nokta olduğunu düşünüyorum. Yalnızca ilişkilendirilebilir dizideki anahtarlarla ilgileniyorsanız ve tüm değerler '1' ise, o zaman 'anahtarları' bir dizide değerler olarak saklayın.

Onun yerine:

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

kullanın:

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

Bunun tek dezavantajı, belirli bir anahtarın bu kadar kolay ayarlanıp ayarlanmadığını belirleyememenizdir. Bkz bu cevabı için javascript fonksiyonu inArray o probleme bir cevap. Sunulan çözümle ilgili bir sorun, a.hasValue('key')bundan biraz daha yavaş olacak olmasıdır a['key']. Bu sizin kodunuzda önemli olabilir veya olmayabilir.


3

Bir Javascript nesnesinin "anahtarlarını" doğrudan değiştirmenin kısa bir yolu yoktur. Gerçekten bunun için tasarlanmadı. Verilerinizi normal bir nesneden (veya örnek kodunuzun önerdiği gibi bir Diziden) daha iyi bir şeye yerleştirme özgürlüğüne sahip misiniz?

Öyleyse ve sorunuz "Anahtarlar üzerinde sıralı sırayla yinelemek istiyorsam hangi sözlük benzeri nesneyi kullanmalıyım?" o zaman şöyle bir nesne geliştirebilirsiniz:

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]); }

Verilerin normal bir nesnede olduğu gerçeği üzerinde hiçbir kontrolünüz yoksa, bu yardımcı program normal nesneyi tam işlevli sözlüğünüze dönüştürür:

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

Bu, basitlik için bir nesne tanımıydı (yeniden kullanılabilir bir yapıcı işlevi yerine); irade ile düzenleyin.


2

İlk fordöngüdeki anahtarları alın , sıralayın, 2. fordöngüde sıralanan sonucu kullanın .

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]);

2

Sen kullanabilirsiniz keysgelen işlevi underscore.js anahtarlarını almak için kütüphaneye, sonra sort()dizi yöntem sıralamak için:

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

Alt keysçizginin kaynak kodundaki işlev:

// 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);
};

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>

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>');
}


0

@ Luke-schafer'ın prototip fikrini gerçekten çok beğeniyorum, ancak prototiplerle ilgili sorunlar hakkında söylediklerini de duyuyorum. Basit bir işlevi kullanmaya ne dersiniz?

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);

Bu, prototiplerle ilgili sorunları ortadan kaldırıyor ve yine de nesneler için sıralı bir yineleyici sağlıyor gibi görünüyor. Aslında bir JavaScript uzmanı değilim, bu yüzden bu çözümün gözden kaçırdığım gizli kusurları olup olmadığını bilmek isterim.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.