Ітерація через асоціативний масив Javascript у відсортованому порядку


109

Скажімо, у мене є асоціативний масив Javascript (він же хеш, ака словник):

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

Як я можу перебирати клавіші в упорядкованому порядку? Якщо це допомагає спростити речі, значення мені навіть не потрібні (вони всі просто число 1).


11
чому ви використовуєте нову конструкцію Array (), а потім використовуєте її як об’єкт?
Люк Шафер

@Luke .. Я це робив і спочатку, виходячи з фону PHP. Я зараз дізнався, хоча :)
Алекс

20
@Luke: тому що я недосвідчений, здається. Чи можете ви відповісти правильним способом у відповіді?
Майк

4
Ви можете просто створити будь-який об’єкт. У Javascript немає різниці між словником / "названим масивом" та звичайним об'єктом. Тому ви можете отримати доступ до ['b'] з ab і навпаки. Найкоротший спосіб створення об’єкта - це a = {};.
Lodewijk

Відповіді:


124

Ви не можете перебрати їх безпосередньо, але ви можете знайти всі ключі, а потім просто сортувати їх.

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

Однак не потрібно робити змінну 'a' масивом. Ви насправді просто використовуєте його як об’єкт і маєте створити його так:

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

28
Ви завжди повинні перевірити forцикл, якщо obj.hasOwnProperty(key).
viam0Zah

3
@Lalit - якщо ви маєте на увазі коментар Торока, це тому, що у вас нічого не заважає прототипу об'єкта, на який ви не можете покластися.
Люк Шафер

1
+1 до Торока. Було б добре, якби відповідь включала hasOwnProperty ().
Джон Онстотт

136

Ви можете використовувати вбудований метод Object.keys :

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

(Примітка. Це не працює у дуже старих браузерах, які не підтримують EcmaScript5, зокрема IE6, 7 та 8. Детальну інформацію про сучасну статистику див. У цій таблиці )


@ michael667 Можливо, тому, що IE 7 і 8 все ще широко використовуються (на жаль, спасибі MS)
Олександр Рейфінгер

1
IE7 знаходиться на рівні 0,5%, а IE8 - на 8%, ніж на даний момент.
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

Я люблю цього, дякую. ось мій код, що використовує це, $ (Object.keys (список)). map (функція (i, e) {return n + '=' + список [n];}). get (). join ('&'); // concat for url querystring
Elaine

1
Оновлення 2016 року: Мабуть, це буде прийнята відповідь
rinogo

14

можна навіть прототипувати його на об'єкт:

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

та використання:

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

3
Я відповів на цю відповідь, це здавалося цілком непоганим, але виявилося, що воно порушує jquery :( stackoverflow.com/questions/1827458/… і взагалі вважається дуже поганою ідеєю "Ніколи не слід поширювати Object.prototype. Це набагато більше, ніж break jQuery; він повністю порушує "JavaScript-об'єкт-хештелі" функцію Javascript. Не робіть цього. Ви можете попросити Джона Резіга, і він скаже вам те саме ".
msanjay

Знаєш, що? Я теж ненавиджу прототипи :) Я ніколи їх не використовую і активно відштовхую від їх використання. Я почував це так 3,5 років тому, коли я писав цю відповідь, але все одно запропонував її ... дякую за надання інформації. На відміну від цього, НЕ МОГУТЬ порушувати рамки, як вони ВИНАГИ використовують hasOwnProperty під час ітерації об'єктів
Лука Шафер

Ось приклад використання значень, а не клавіш для сортування , зберігаючи key -> valueзв’язок.
Xeoncross

6

Я погоджуюся з відповіддю Свінглі , і я вважаю, що важливим моментом є відсутність багатьох цих більш детальних рішень. Якщо вас стосуються лише ключі в асоціативному масиві, а всі значення "1", просто зберігайте "ключі" як значення в масиві.

Замість:

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

Використання:

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

Єдиним недоліком цього є те, що ви не можете визначити, чи встановлюється конкретна клавіша так легко. Дивіться цю відповідь на функцію javascript у inArray, щоб отримати відповідь на цю проблему. Одне питання з представленим рішенням полягає в тому, що a.hasValue('key')це буде трохи повільніше, ніж a['key']. Це може не мати значення у вашому коді.


3

Немає стислого способу безпосередньо маніпулювати "клавішами" об'єкта Javascript. Це насправді не призначено для цього. Чи маєте ви свободу вводити свої дані в щось краще, ніж звичайний об'єкт (або масив, як підказує ваш зразок коду)?

Якщо так, і якщо ваше запитання могло б бути переосмислено як "Який об’єкт, подібний до словника, я повинен використовувати, якщо хочу перебрати ключі в упорядкованому порядку?" то ви можете розробити такий об’єкт:

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

Якщо у вас немає контролю над тим, що дані знаходяться у звичайному об'єкті, ця утиліта перетворить звичайний об'єкт у ваш повністю функціональний словник:

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

Це було визначення об'єкта (замість функції конструктора для багаторазового використання) для простоти; редагувати за бажанням


2

Отримайте ключі в першому forциклі, відсортуйте його, використовуйте відсортований результат у другому forциклі.

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

Ви можете використовувати keysфункцію з бібліотеки underscore.js для отримання ключів, а потім sort()методом масиву для їх сортування:

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

keysФункції в вихідному коді Underscore в:

// 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, але також чую, що він говорить про проблеми з прототипами. Що з використанням простої функції?

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

Це, здається, усуває проблеми з прототипами і все ще забезпечує відсортований ітератор для об'єктів. Я насправді не є гуру JavaScript, тому я хотів би знати, чи є в цьому рішенні приховані недоліки, які я пропустив.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.