Поиск по этому блогу

воскресенье, 2 декабря 2012 г.

Сортировка списка объектов на javascript... (Sorting objects in javascript)

Здравствуйте, давайте поговорим о сортировках
, но нет, не о алгоритмах сортирования,а о написании функций-компараторов участвующих в сравнении двух элементов  Для начала вспомним как применяются такие функции.
var arr = [1,5,7,3,2];
//обычная сортировка
arr.sort(); //[1, 2, 3, 5, 7]
//сортировка с применение функции-компаратора
function myCompar (a, b){ 
    if (a > b) {
        return -1;
    } else if (a < b) {
        return 1;
    } else {
        return 0;
    }
};
arr.sort(myCompar); //[7, 5, 3, 2, 1]
С приведенного выше примера видно что функция-компаратор ни что иное как: функция принимающая сравниваемые элементы в виде двух аргументов и возвращает результат их сравнения (1, -1, 0). В примере я использовал функцию-компаратор для реализации обратной сортировки числового массива, на практике же она чаще используется для сортировки массива объектов (хэшей) или для применения перед сравнением к элементам дополнительных преобразований (parseInt(a, 10), a.toLowerCase()... ). Написание функций-компараторов для сложных типов данных может занять много времени и места в вашем коде и зачастую такие сортировки нечитабельные  Давайте попробуем оптимизировать и упростить данный процесс. За основу был взят код Triptych'a, после чего он был изменен и оброс рюшечками :).
function get_sorter_by (field, reverse, primer) {
 if (field && field.constructor == Array) {
  var sorters = [];
  for (var i = 0; i < field.length; i += 1) {
   sorters.push(get_sorter_by(field[i][0], field[i][1], field[i][2]));
  };
  return function (a, b) {
   var res = 0;
   for (var i = 0; i < sorters.length; i += 1) {
    res = sorters[i](a, b);
    if (res != 0) break;
   };
   return res;
  }
 }

 var key;
 if (field) {
  key = primer ? function (o) {return primer(o[field])} : function (o) {return o[field]};
 }
 else {
  key = primer ? function (o) {return primer(o)} : function (o) {return o};
 }

 return function (a, b) {
  var A = key(a), B = key(b);
  return ( A < B ? +1 :
    (A > B ? -1 : 0)) * [-1,1][+!!reverse];
 }
};
Итак, функция get_sorter_by принимает 3 параметра :
field
Поле по которому будет проводится сравнение.
reverse
Признак "обратной сортировки".
primer
Функция для предварительной обработки сортируемых полей.
Аргумент field может быть задан в виде массива массивов аргументов функции для организации дополнительной сортировки (группировки) результатов.
function get_sorter_by (field, reverse, primer) {
 if (field && field.constructor == Array) {
  var sorters = [];
  for (var i = 0; i < field.length; i += 1) {
   sorters.push(get_sorter_by(field[i][0], field[i][1], field[i][2]));
  };
  return function (a, b) {
   var res = 0;
   for (var i = 0; i < sorters.length; i += 1) {
    res = sorters[i](a, b);
    if (res != 0) break;
   };
   return res;
  }
 }

 var key;
 if (field) {
  key = primer ? function (o) {return primer(o[field])} : function (o) {return o[field]};
 }
 else {
  key = primer ? function (o) {return primer(o)} : function (o) {return o};
 }

 return function (a, b) {
  var A = key(a), B = key(b);
  return ( A < B ? +1 :
    (A > B ? -1 : 0)) * [-1,1][+!!reverse];
 }
};

var arr = [
    {name : 'Joe', weight : 100, kids : 1},
    {name : 'Hloe', weight : 57, kids : 2},
    {name : 'Molly', weight : 53, kids : 0},
    {name : 'Shon', weight : 73, kids : 1}
];
function toLowerCase (s){return s.toLowerCase()};
var mySorts = {
    name_asc : get_sorter_by('name', 0, toLowerCase),
    name_desc : get_sorter_by('name', 1, toLowerCase),
    weight60_asc : get_sorter_by('weight', 0, function (w) {return Math.abs(w-60);}),
    weight60_desc : get_sorter_by('weight', 1, function (w) {return Math.abs(w-60);}),
    kids_asc : get_sorter_by([
        ['kids', 0],
        ['name', 0, toLowerCase]
    ]),
    kids_desc : get_sorter_by([
        ['kids', 1],
        ['name', 0, toLowerCase]
    ])
};

arr.sort(mySorts.name_asc); // Сортировка по имени
arr.sort(mySorts.weight60_desc); // Сортировка по приближенности веса к 60 в обратном порядке
arr.sort(mySorts.kids_asc); // Сортировка по количеству детей и по имени

Комментариев нет:

Отправить комментарий