Сортировка наблюдаемого массива в нокауте

У меня есть наблюдаемый массив в нокауте объектов человека. Я хотел уметь сортировать список лиц по фамилии. Проблема состоит в том, что в списке есть несколько дубликатов фамилий. В результате, когда имеется более одной фамилии, первые имена появляются по мере их нахождения. Я хотел бы иметь возможность сортировать массив по фамилии и, когда есть более одной фамилии, попробуйте также сортировать по имени. Я использую текстовый ввод для пользователя, чтобы начать вводить фамилию. Результаты привязаны к шаблону, который отображает все совпадения.

<input data-bind="value: filter, valueUpdate: 'afterkeydown'">

И вот мой фильтр фильтра для нокаута:

function Item(firstname, lastname) {
     this.firstname = ko.observable(firstname);
     this.lastname = ko.observable(lastname);
}

var playersViewModel = {
     items: ko.observableArray([]),
     filter: ko.observable("")
};
var players;

$(function() {
    playersViewModel.filteredItems = ko.computed(function() {
         var filter = this.filter().toLowerCase();
         if (!filter) {
              return this.items();
         } else {
              return ko.utils.arrayFilter(this.items(), function(item) {
                    return ko.utils.stringStartsWith(item.lastname().toLowerCase(), filter);
              });
         }
    }, playersViewModel);

    $.getJSON('./players.json', function(data) {
        players = data.players;
        playersViewModel.players = ko.observableArray(players);
        ko.applyBindings(playersViewModel);    
        var mappedData = ko.utils.arrayMap(players, function(item) {
             return new Item(item.firstname,item.lastname);
        });
        playersViewModel.items(mappedData);
    });    
});

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

Joe Bailey
Jack Brown
Adam Brown
Bob Brown
Jim Byrd

Я хотел бы, чтобы имена повторяющихся имен также отсортировались по именам:

Joe Bailey
Adam Brown
Bob Brown
Jack Brown
Jim Byrd

Ответ 1

Наблюдаемые массивы KnockoutJS предлагают функцию сортировки, поэтому относительно легко сортировать массив данных в вашем пользовательском интерфейсе (независимо от естественного порядка данных).

data-bind="foreach: items.sort(function (l, r) { return l.lastName() > r.lastName() ? 1 : -1 })"

Вам не нужно предварительно сортировать/повторно сортировать исходные данные, если вы сортируете до привязки (или перефилирования из-за сортировки), тогда вы делаете это неправильно.

Тем не менее, то, что вы просите, состоит в сортировке по двум значениям, фамилии, затем имени.

Вместо "l.lastName() > r.lastName()? 1: -1" рассмотрим следующее:

l.lastName() === r.lastName() 
    ? l.firstName() > r.firstName() ? 1 : -1
    : l.lastName() > r.lastName() ? 1 : -1

Это может быть более эффективным, я уверен. В принципе у вас есть три условных выражения:

  • Являются ли последние имена равными?
  • Если это так, сравните имена и верните результат.
  • Повторите, сравните фамилии и верните результат.

Я просмотрел ваш код, и я не вижу такой функции сортировки.

Это похоже на ответ Майкла Наилучшего, однако я попытался разъяснить WHERE, чтобы обрабатывать сортировку (в вашем примере привязки, первый пример) и КАК достичь того вида, который вы ищете (несколько опорных точек).

data-bind="foreach: items().sort(function (l, r) { return (l.lastName() == r.lastName()) ? (l.firstName() > r.firstName() ? 1 : -1) : (l.lastName() > r.lastName() ? 1 : -1) })"

Естественно, это может стать громоздким, поскольку вы вводите больше векторов сортировки, таких как обратные или дополнительные данные, и поэтому вы должны реализовать функцию фильтра, которая выполняет вышеуказанную оценку для вас:

data-bind="foreach: items().sort(my.utils.compareItems)"

Ответ 2

Если вы убедитесь, что ваш players.json возвращает отсортированные имена, все будет в порядке. Если он загружает их из базы данных, вам нужно добавить первое поле имени в предложение ORDER BY.

Если вы хотите выполнить сортировку в Javascript, вы можете сделать это сразу после загрузки из службы:

players.sort(function(player1, player2) {
    return player1.lastname.localeCompare(player2.lastname) ||
        player1.firstname.localeCompare(player2.firstname);
});

Ответ 3

У меня возникли проблемы с сортировкой наблюдаемого массива, я не видел никаких результатов в моем коде.

Сначала вам нужно отсортировать результаты, полученные с помощью запроса ajax/getJSON, прежде чем вы вернете новые элементы в свой массив.

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

См. пример ниже.

players(ko.utils.arrayMap(result, function (item) {
                    result.sort(function (l, r) {
                        return l.name == r.name ? 0 : (l.name < r.name ? -1 : 1);
                    });
                return new Player(item);
            }));
  • получить данные с помощью AJAX/getJSON
  • Сортировка результата запроса в выбранный вами массив

Ответ 4

Для этого нужно использовать два вида. В первой сортировке сортируйте по словам фамилии и во второй сортировке Сначала найдите по имени, если более двух человек имеют одинаковую фамилию, чем сортировать по первому имени в их местоположении, используя некоторый стандартный алгоритм сортировки....