Подготовить массив к сортировке в замыкании

Согласно моим исследованиям и поиску в Google, Javascript, похоже, не поддерживает сортировку с учетом локали и сравнение строк. Существует localeCompare(), но он сообщено о различиях в браузерах и о невозможности явного указания локали используется (локаль ОС не всегда нужная). Есть некоторые намерения добавить поддержку сопоставления внутри ECMAScript, но до этого мы сами по себе. И в зависимости от того, насколько последовательны результаты в разных браузерах, может быть, мы навсегда останемся одни :(.

У меня есть следующий код, который делает алфавитную сортировку массива. Это сделано с учетом скорости, а идеи взяты из https://stackoverflow.com/a/11598969/1691517, к которому я сделал некоторые улучшения скорости.

В этом примере массив слов состоит из 13 элементов, а функция сортировки вызывается 34 раза. Я хочу заменить некоторые буквы в массиве слов (вам не обязательно знать, какие замены сделаны, потому что это не главное в этом вопросе). Если я делаю эти замены в функции сортировки (той, которая начинается с return function(a, b)), код неэффективен, потому что замены выполняются более одного раза для каждого члена массива. Конечно, я могу сделать эти замены вне этого закрытия, я имею в виду перед строкой words.sort(sortbyalphabet_timo);, но это не то, что я хочу.

Вопрос 1. Можно ли изменить массив слов между строками "ПОДГОТОВКА НАЧАЛА" и "ПОДГОТОВКА ЗАВЕРШАЕТСЯ", чтобы функция сортировки использовала измененный массив слов?

Вопрос 2. Можно ли вводить аргументы для замыкания, чтобы код между PREPARATION STARTS и PREPARATION ENDS мог их использовать? Я пробовал это без успеха:

var caseinsensitive = true;
words.sort( sortbyalphabet_timo(caseinsensitive) );

И вот, наконец, пример кода, и готовый к запуску пример находится в http://jsfiddle.net/3E7wb/< /а>:

var sortbyalphabet_timo = (function() {
  // PREPARATION STARTS
  var i, alphabet = "-0123456789AaÀàÁáÂâÃãÄäBbCcÇçDdEeÈèÉéÊêËëFfGgHhIiÌìÍíÎîÏïJjKkLlMmNnÑñOoÒòÓóÔôÕõÖöPpQqRrSsTtUuÙùÚúÛûÜüVvWwXxYyÝýŸÿZz",
  index = {};

  i = alphabet.length;
  while (i--) index[alphabet.charCodeAt(i)] = i;
  // PREPARATION ENDS

  return function(a, b) {
    var i, len, diff;

    if (typeof a === "string" && typeof b === "string") {
      (a.length > b.length) ? len = a.length : len = b.length;
      for (i = 0; i < len; i++) {
        diff = index[a.charCodeAt(i)] - index[b.charCodeAt(i)];

        if (diff !== 0) {
          return diff;
        }
      }
      // sort the shorter first
      return a.length - b.length;
    } else {
      return 0;
    }
  };
})();

var words = ['tauschen', '66', '55', '33', 'täuschen', 'andern', 'ändern', 'Ast', 'Äste', 'dosen', 'dösen', 'Donaudam-0', 'Donaudam-1'];
$('#orig').html(words.toString());
words.sort(sortbyalphabet_timo);
$('#sorted').html(words.toString());`

person Timo Kähkönen    schedule 26.09.2012    source источник
comment
У вас очень интересный алфавит.   -  person jbabey    schedule 26.09.2012
comment
Это? Функция сделана с намерением, чтобы пользователь мог добавить любой алфавит, который он / она хочет. Это только пример одного возможного порядка символов. Пожалуйста, используйте тот, который вы хотите.   -  person Timo Kähkönen    schedule 26.09.2012


Ответы (1)


Можно ли изменить массив слов между строками «НАЧАЛО ПОДГОТОВКИ» и «ЗАВЕРШЕНИЕ ПОДГОТОВКИ», чтобы функция сортировки использовала измененный массив слов?

Нет, не совсем. У вас нет доступа к самому массиву, ваша функция только строит функцию сравнения, которая позже используется, когда .sort вызывается для массива. Если вам нужно изменить массив, вам нужно написать функцию, которая получает его в качестве аргумента; например, вы можете добавить метод на Array.prototype. Это будет выглядеть как

function mysort(arr) {
    // Preparation
    // declaration of compare function
    // OR execution of closure to get the compare function
    arr.sort(comparefn);
    return arr;
}

Можно ли вводить аргументы в замыкание, чтобы код между PREPARATION STARTS и PREPARATION ENDS мог их использовать?

Да, конечно - это причина использования замыканий :-) Однако вы не можете использовать sortbyalphabet_timo(caseinsensitive) с вашим текущим кодом. Закрытие, которое у вас есть, немедленно вызывается (называется IIFE) и возвращает функцию сравнения, которую вы передаете в sort, как в вашей демонстрации.

Если вы хотите, чтобы sortbyalphabet_timo было замыканием, а не результатом, вы должны удалить скобки после него. Вы также можете использовать там аргументы, которые доступны во всей области закрытия (включая функцию сравнения):

var sortbyalphabet_timo_closure = function(caseinsensitive) {
    // Preparation, potentially using the arguments
    // Declaration of compare function, potentially using the arguments
    return comparefn;
}
// then use
words.sort(sortbyalphabet_timo_closure(true));

В настоящее время вы делаете это:

var sortbyalphabet_timo_closure = function(/*having no arguments*/) {
    // Preparation, potentially using the arguments
    // Declaration of compare function, potentially using the arguments
    return comparefn;
}
var sortbyalphabet_timo = sortbyalphabet_timo_closure();
// then use
words.sort(sortbyalphabet_timo);

… который просто кэширует результат выполнения замыкания, если вам нужно выполнить сортировку несколько раз.

person Bergi    schedule 26.09.2012
comment
Спасибо! Почему ваше предложение без закрытия настолько медленное по сравнению с закрытой версией? Замыкающая версия примерно в 25 (или 198 в Safari) раз быстрее: jsperf.com/collation-string -сортировка/12 - person Timo Kähkönen; 27.09.2012
comment
Гм, вы не передали функцию сравнения, а замыкание в sort(). Я думаю, что из jsperf.com/collation-string-sorting/14 должно быть очевидно почему один (немного) быстрее. - person Bergi; 27.09.2012
comment
Этот ответ стоит +1, потому что здесь мы подошли к истине, стоящей за моим вопросом. Я спросил, возможно ли это, но реальный смысл в том, как я могу этого достичь. Как я могу получить все это: скорость версии закрытия (поэтому ничего не делается несколько раз, если это не нужно), использование аргументов для выбора, например. нечувствительность и изменить массив слов до его сортировки? Я требую чего-то невозможного? - person Timo Kähkönen; 27.09.2012
comment
Да. Использование аргументов и скорости кэшированного-закрытия-результата немного противоречиво. Изменение массива не имеет ничего общего с закрытием. - person Bergi; 27.09.2012
comment
Модификация массива слов, конечно, может быть выполнена вне замыкания. Если мы хотим, например. сделать сортировку нечувствительной, мы можем преобразовать элементы массива в нижний или верхний регистр, а если мы хотим сделать сортировку нечувствительной к диакритическим знакам, мы можем преобразовать все диакритические знаки в неакцентные. - person Timo Kähkönen; 27.09.2012
comment
Это может быть оффтоп, но поскольку правила сортировки сильно различаются в разных локалях, строгого сравнения по буквам недостаточно. Функция вопроса предполагает, что все символы имеют одинаковый вес. Если «v» и «w» являются базовыми буквами, функция успешно выполняет сортировку, но если «w» является вариантом «v», возникает проблема. Другая сложность - двух- или трехбуквенные комбинации, например. 'ндж', 'дз'. Таким образом, мы должны изменить как строку алфавита, чтобы принять больше вариаций, так и массив слов, чтобы сделать его побуквенно сравнимым в этих особых случаях. - person Timo Kähkönen; 27.09.2012
comment
Мне очень не хватает готовой js-библиотеки для этого, но пока не нашел. - person Timo Kähkönen; 27.09.2012