Ассоциативные массивы и их сортировка
21/03/2007 23:53 — savostin
Ассоциативные массивы (хеши) - это масивы, в которых в качестве индекса используется не число. Удобно для хранения не последовательностей, а, например, параметров. Создание хешей ничем не отличается от массивов:
"Сложностью" в данном случае с хешами будет сортировка, ведь порядок элементов далеко не однозначен (скорее всего в порядке добавления в хеш, но вариантов много). Более того, мы хотим отсортировать хеш по значениям параметров объектов, хранящихся в нем. Пишем функцию:
Как это применять:
Кому не нравится такая реализация, могут попробовать Array.prototype сделать, добавить обратную сортировку, и пр. украшательства.
Замечание: из-за конструкции return arguments[0][1][name] - arguments[1][1][name] функция сортирует только по числовым значениям параметров. При желании можно изменить на что-то типа return arguments[0][1][name] > arguments[1][1][name] ? 1 : -1 и по идее будет работать с любыми типами параметров.
Рабочий пример прилагается. Комментарии приветствуются.
var Hash = new Array();
Hash['first key'] = 5;
Hash['second key'] = 25;
Hash['some key'] = 11;
Так же, как и в массивах, в хешах можно хранить объекты:
var Hash = new Array();
var a = Hash['first_key'] = new Object();
a.someProp = 25;
a.anotherProp = 'Some another value';
a = Hash['second_key'] = new Object();
a.someProp = 15;
a.anotherProp = 'Some another value';
Следует обратить внимание на удобство обращения в таким хешам по ключу без скобок (при условии, конечно, что в имени ключа нет пробела): Hash.first_key.someProp"Сложностью" в данном случае с хешами будет сортировка, ведь порядок элементов далеко не однозначен (скорее всего в порядке добавления в хеш, но вариантов много). Более того, мы хотим отсортировать хеш по значениям параметров объектов, хранящихся в нем. Пишем функцию:
// IN: исходный хеш, имя параметра по которому сортируем
// OUT: отстортированный хеш
function ASort(aInput, name){
var aTemp = []; // временный массив
for (var sKey in aInput){aTemp.push([sKey, aInput[sKey]]);} // ключ и его значение
aTemp = aTemp.sort(function (){return arguments[0][1][name] - arguments[1][1][name]}); // сортируем временный массив
var aOutput = []; // это мы вернем
for (var nIndex = 0; nIndex < aTemp.length; nIndex++) {aOutput[aTemp[nIndex][0]] = aTemp[nIndex][1];}// собственно создаем выходной массив в нужном порядке
delete aTemp; // убираем за собой
delete aInput; // по идее исходный массив тоже нужно удалить, но далеко не всегда. можно вынести за пределы функции, но не забывать там убирать мусор
return aOutput;
}
Как это применять:
var SortedHash = ASort(Hash, 'someProp');
Кому не нравится такая реализация, могут попробовать Array.prototype сделать, добавить обратную сортировку, и пр. украшательства.
Замечание: из-за конструкции return arguments[0][1][name] - arguments[1][1][name] функция сортирует только по числовым значениям параметров. При желании можно изменить на что-то типа return arguments[0][1][name] > arguments[1][1][name] ? 1 : -1 и по идее будет работать с любыми типами параметров.
Рабочий пример прилагается. Комментарии приветствуются.
- Блог пользователя savostin
- Войдите или зарегистрируйтесь, чтобы оставлять комментарии




Комментарии
Хотелось бы видеть не просто теоритические выкладки, а и какое-то красивое применение на практике. Собственно, даже так: теоритические выкладки ПО ПОВОДУ какого-то применения на практике :) Желательно с рабочим примером :)
дык
Рабочий пример приаттачен. Я конечно понимаю, что это не летающие снежинки, но для тех, кто воспринимает "web 2.0" шире, чем XMLHttpRequest, думаю будет полезным
Не надо мне про снежинки, был пример ;-/
А вообще мне нравится как http://www.artlebedev.ru/tools/technogrette/ сделано. Все так классно иллюстрировано, типа http://www.artlebedev.ru/tools/technogrette/js/zoom/ :)
это ж бох ;-)
так и быть
сегодня подготовлю что-нибудь более визуальное ;-)
Давай :)
push, если не macie, иначе arr[arr.length] = ...;
вместо этого:
for (var nIndex = 0; nIndex < aTemp.length; nIndex++)это:
for (var nIndex = 0, l = aTemp.length; nIndex < l; nIndex++)можно ещё по кол-ву букв в ключах или по буквам, исключая цифры :)
спасибо :)
Объявить функцию сортировки как прототип
судя по всему объвить функцию сортировки как прототип будет непросто.
var arr = Array();
Array.prototype.func = function(){};
for (prop in arr) alert(prop);
выходит что прототип функции становиться элементом массива (°_°)
странно что при этом стандартные методы ведут себя иначе
не подскажете как избежать подобного поведения массива? можно конечно во всех циклах определять не является ли свойство методом сортировки, но это не выглядит как изящное решение...
UPD: судя по всему это невозможно, тк стандартные методы имеют аттрибут DontEnum равный true, а все пользовательские - false и установить этот атрибут в другое значение не представляется возможным.
Ну, есть один трюк
Array.prototype.ASort = function(name){
var aInput = this;
var aTemp = [];
for (var sKey in aInput){if (typeof(aInput[sKey]) != 'function'){aTemp.push([sKey, aInput[sKey]]);}} // ключ и его значение за исключением функций
aTemp = aTemp.sort(function (){return arguments[0][1][name] - arguments[1][1][name]});
var aOutput = new Object(); // вот и вся хитрость
for (var nIndex = 0; nIndex < aTemp.length; nIndex++) {aOutput[aTemp[nIndex][0]] = aTemp[nIndex][1];}
delete aTemp;
//delete aInput;// это тут наверное уже совсем не нужно, см. применение
return aOutput;
}
И применяем:
ClientsSorted = Clients.ASort('height');document.write('<ol>');
for(var i in ClientsSorted)
document.write('<li>' + i + ' - ' + Clients[i].height + 'см.</li>');
document.write('</ol>');
Обращаю внимание, мы изменили тип, т.е. typeof(Clients) != typeof(ClientsSorted) и посему нельзя дальше делать ClientsSorted.ASort(), только Clients.ASort(), что думаю некритично...
А все потому, что JavaScript почти не различает типы Array и Object...
это то да, но если в коде есть други объекты Array, то получаем то же самое
придётся всегда держать в уме что у Array появилось новое свойство и нужно использовать Object
естественно когда хочешь добавить прототип сортировки в готовый проект, получишь массу сюрпризов не самого приятного свойства)
хотя мысль конечно хорошая, спасибо) но судя по всему создание прототипов для массивов и объектов в js это плохое решение((
не совсем
Использовать for...in для массивов крайне не рекомендуется, посему при правильном выборе типов данных плохого ничего не должно случиться (потому что Array.length не изменяется). Как вы заметили я сделал Array.prototype.ASort, а не Object.prototype.ASort. Это не совсем правильно, ведь у нас по большому счету Object сортируется, но для данной локальной задачи думаю не так важно. Основная мысль в том, что Array в Object преобразовывать можно безболезненно, а вот Object в Array (и уж тем более использовать Object как Array) не рекомендовал бы.
ЗЫ. это как всегда лишь иллюстрация принципов, а не готовая библиотека.