Итерация по объекту JavaScript в порядке сортировки на основе определенного значения ключа дочернего объекта

Краткая версия: я ищу JavaScript-эквивалент Perl's

for my $key ( sort { $hash{$a}{foo} cmp $hash{$b}{foo} } keys %hash ) {
    # do something with $key
}

Подробнее:

У меня есть объект JSON, который состоит из множества других объектов JSON, которые имеют идентичные свойства друг другу, например хеш хешей в Perl: например:

var peopleobj = { 
    "0291" : { "Forename" : "Jeremy", "Surname" : "Dyson" },
    "0398" : { "Forename" : "Billy", "Surname" : "Bunter" },
    "6714" : { "Forename" : "Harry", "Surname" : "Peterson" },
    "9080" : { "Forename" : "Barry", "Surname" : "Mainwaring"}
}

Я хочу перебрать объекты в peopleobj в порядке значений фамилий, например, чтобы распечатать имена в порядке фамилий. Простые решения JavaScript или jQuery будут работать в контексте, в котором они развертываются.

Заранее благодарим за ваше драгоценное время.


person Jonah    schedule 28.10.2010    source источник
comment
Большое спасибо Даниилу - это действительно полезно!   -  person Jonah    schedule 28.10.2010
comment
Просто деталь: эта вещь называется не объектом JSON, а объектом JavaScript; JSON - это просто обозначение объекта JavaScript.   -  person Marcel Korpel    schedule 28.10.2010
comment
Спасибо за разъяснения, очень признателен. Верно подмечено!   -  person Jonah    schedule 03.11.2010


Ответы (1)


Интересный вопрос ... Одно из простых решений JavaScript - создать индекс для ваших объектов в отдельном массиве на основе свойства 'Surname'. Примерно так 1:

var peopleobj = { 
   "0291" : { "Forename" : "Jeremy", "Surname" : "Dyson" },
   "0398" : { "Forename" : "Billy", "Surname" : "Bunter" },
   "6714" : { "Forename" : "Harry", "Surname" : "Peterson" },
   "9080" : { "Forename" : "Barry", "Surname" : "Mainwaring" }
};

var index = [];

// build the index
for (var x in peopleobj) {
   index.push({ 'key': x, 'Surname': peopleobj[x]['Surname'] });
}

// sort the index
index.sort(function (a, b) { 
   var as = a['Surname'], 
       bs = b['Surname']; 

   return as == bs ? 0 : (as > bs ? 1 : -1); 
}); 

Теперь вы можете перебирать массив index:

for (var i = 0; i < index.length; i++) {
   console.log(peopleobj[index[i]['key']]['Surname']);
}

Результат (проверено в консоли Firebug):

Bunter
Dyson
Mainwaring
Peterson

Возможно, вы захотите обернуть это в какой-то многоразовый объект Iterator, хотя было бы трудно получить столь же сжатый, как Perl:

// Our reusable Iterator class:
function MyIterator (o, key) {
   this.index = [];
   this.i = 0;
   this.o = o;

   for (var x in o) {
      this.index.push({ 'key': x, 'order': o[x][key] });
   }

   this.index.sort(function (a, b) { 
      var as = a['order'], 
          bs = b['order']; 

      return as == bs ? 0 : (as > bs ? 1 : -1); 
   }); 

   this.len = this.index.length;
}

MyIterator.prototype.next = function () {
   return this.i < this.len ?
          this.o[this.index[this.i++]['key']] :
          null;
};

Затем используйте его следующим образом:

// Our JavaScript object:
var peopleobj = { 
   "0291" : { "Forename" : "Jeremy", "Surname" : "Dyson" },
   "0398" : { "Forename" : "Billy", "Surname" : "Bunter" },
   "6714" : { "Forename" : "Harry", "Surname" : "Peterson" },
   "9080" : { "Forename" : "Barry", "Surname" : "Mainwaring" }
};

// Build the Iterator object, using the 'Surname' field:
var surnameIter = new MyIterator(peopleobj, 'Surname');

// Iterate:
var i;

while (i = surnameIter.next()) {
   console.log(i['Surname'] + ' ' + i['Forename']);
}

Результат:

Bunter Billy
Dyson Jeremy
Mainwaring Barry
Peterson Harry

1 Вы можете использовать _9 _, чтобы убедиться, что свойства принадлежат вашему объекту и не наследуются от Object.prototype:

for (var x in peopleobj) {
   if (peopleobj.hasOwnProperty(x)) {
      index.push({ 'key': x, 'Surname': peopleobj[x]['Surname'] });
   }
}
person Daniel Vassallo    schedule 28.10.2010
comment
+1. Хороший ответ, хотя функция сравнения, переданная в sort(), должна возвращать число, а не логическое значение. Я бы предложил что-то вроде function (a, b) { var as = a.Surname., bs = b.Surname; return as == bs ? 0 : (as > bs ? 1 : -1); } - person Tim Down; 28.10.2010
comment
Это отличное решение, спасибо за объяснение. Я использовал эту плюс преобразованную строку в Date в функциях сортировки и получил именно то, что мне нужно. - person Akers; 09.01.2012