О функции сортировки для JavaScript - PullRequest
5 голосов
/ 22 июня 2011

Справочная информация:

По мере необходимости в какой-то задаче мне нужна простая функция сортировки.Для простоты я написал другую функцию для обертывания встроенной функции сортировки следующим образом:

function sortBy(obj, extra, func){
    if(typeof func == 'function'){
        f = func;
    } else if(typeof extra != 'function'){
        eval('function f(a, b, ai, bi, e){return ' + func + '}');
    } else {
        var f = extra;
        extra = null;
    }

    var res = [];
    for(var i in obj){
        if(obj.hasOwnProperty(i)){
            obj[i]._k_ = i;
            res.push(obj[i]);
        }
    }

    res.sort(function(a, b){
        if(f(a, b, a._k_, b._k_, extra)){
            return 1;
        } else {
            return -1;
        }
    })

    return res;
}

Мои попытки:

  1. Позволяют отсортировать объект напрямую
  2. Сохранить исходный объект как хеш-таблицу.
  3. Разрешить простой синтаксис

Например,

var data ={
    12: {age:27, name:'pop', role: 'Programmer'},
    32: {age:25, name:'james', role: 'Accontant'},
    123:{age:19, name:'jerry', role:'Sales Representative'},
    15:{age:22, name:'jerry', role:'Coder'},
    17:{age:19, name:'jerry', role:'Tester'},
    43:{age:14, name:'anna', role: 'Manager'},
    55: {age:31, name:'luke', role:'Analyst'}
};

Существует несколько вариантов использования:

var b = sortBy(data, '', 'a.age < b.age'); // a simple sort, order by age
var b = sortBy(data, 19, 'b.age == e');    // pick up all records of age 19, and put them in the beginning
var b = sortBy(data, function(a, b){return a.name > b.name});  // anonymous sort function is also allowed

ВОПРОС

Хотя это работает так, как и ожидалось в нашем коде, я хотел бы поднять вопрос:

  1. Есть ли потенциальная проблемаоб использовании eval для создания функции сортировки из строки?
  2. Есть ли история о том, что функция сортировки возвращает -1 (отрицательное значение), 0 и 1 (положительное значение)?Можем ли мы изменить код как «return if (f (a, b, a. k , b. k , extra)» вместо возврата 1 или -1? Мы нашлион работает в нашем Firefox и Chrome, но не уверен, насколько это безопасно.

Ответы [ 4 ]

4 голосов
/ 22 июня 2011

1.Есть ли потенциальная проблема с использованием eval для создания функции сортировки из строки?

Не само по себе, но она страдает теми же недостатками, что и вызов других функций стиля eval со строками, например setTimeout()или Function() конструктор.Пока вы доверяете источнику строки, нет никаких реальных проблем.Однако вместо этого я хотел бы использовать конструктор Function:

f = new Function(a, b, ai, bi, e, 'return ' + func);

Это более управляемо и определенно более уместно, чем оценка объявления функции.

2.Есть ли какая-нибудь история о функции сортировки, возвращающей -1 (отрицательный), 0 и 1 (положительный)?

Не совсем понимаю эту часть вашего вопроса, но ваша функция, кажется, не решает, чтосделать, если два сравнения совпадают из сравнения.Вы должны возвращать меньше 0, 0 или больше 0 в зависимости от результата.Для этого лучше всего использовать String.prototype.localeCompare():

return String.prototype.localeCompare.call(a, b);
0 голосов
/ 23 июня 2011
  1. Благодаря Энди мы изменили код на

    var f = new Function ('a, b, ai, bi, e', 'return' + func);

Обратите внимание, что аргументы должны быть переданы в виде строки, проверьте: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function

  1. По поводу второго вопроса, я думаю, это потому, чтомы пытались сделать функцию сортировки более явной.Например,

    sort ([1, 2, 3, 5, 1], '', 'a [1, 1, 2, 3, 5]

Для нас буквальное значение «a Другой пример, «a.age Вот почему я спрашиваю, можем ли мы использовать вместо true или falseиз -1, 0, 1.

Мы продолжаем делать еще несколько небольших тестов и что-то выяснить, хотели бы поделиться со всеми.

Например:

var b = [
    {age:27, name:'pop 2', role: 'Programmer'},
    {age:19, name:'james', role: 'Accontant'},
    {age:19, name:'jerry', role:'Sales Representative'},
    {age:22, name:'jerry', role:'Coder'},
    {age:19, name:'jerry', role:'Tester'},
    {age:14, name:'anna', role: 'Manager'},
    {age:19, name:'luke', role:'Analyst'},
    {age:27, name:'pop', role: 'Programmer'},
    {age:14, name:'anna 2', role: 'Manager'}
];

b.sort(function(a, b) {return a.age - b.age > 0? 1: -1}); // #1
b.sort(function(a, b) {return a.age > b.age});  // #2
b.sort(function(a, b) {return a.age - b.age});  // #3

Хотя приведенные выше сортировки возвращают один и тот же результат, попробуйте следующий:

b.sort(function(a, b) {return a.age - b.age < 0? -1: 1});  // #4

В этом выражении записи по-прежнему упорядочены по возрасту, но порядок в этой же возрастной группе обратный.

# 1 и # 2 случайно совпадают с # 3.Если браузер использует другой алгоритм для реализации функции сортировки, возможно, что # 1 и # 2 будут вести себя как # 4.Если вы строго следите за порядком результата, вам нужно явно вернуть 0, когда 'a' равно элементу 'b'.

Кроме того, как указал Энди, в некоторых случаях (например, # 4), возможно, что ненужные перестановки будут выполнены, если мы не вернем 0 явно, что может повлиять на производительность.

Причина, по которой мы не заметили этого раньше, заключается в том, что нам не важен порядок в пределахгруппа, предоставляющая запись, сортируется по определенному свойству.

0 голосов
/ 22 июня 2011

Попробуйте сделать так, чтобы вы делали eval только для небольшой части:

(скрипка: http://jsfiddle.net/maniator/SpJbN/)

function sortBy(obj, extra, func){
    var f = null;
    if(typeof func == 'function'){
        f = func;
    } else if(typeof extra != 'function'){
        f = function(a, b, ai, bi, e){
            return eval(func); // <-- smaller part
        }
    } else {
        f = extra;
        extra = null;
    }

    var res = [];
    for(var i in obj){
        if(obj.hasOwnProperty(i)){
            obj[i]._k_ = i;
            res.push(obj[i]);
        }
    }

    res.sort(function(a, b){
        if(f(a, b, a._k_, b._k_, extra)){
            return 1;
        } else {
            return -1;
        }
    })

    return res;
}
0 голосов
/ 22 июня 2011

Я думаю, что было бы целесообразно передать функцию, которая выполняет сравнение.так что-то типа

sort(somedata, function(a, b) {
    return a < b;
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...