сохранить observableArrays отсортированным после push - PullRequest
0 голосов
/ 11 июня 2018

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

self.allCourses = ko.observableArray([]);
self.selectedCourses = ko.observableArray([]);

Я поменяю курсами между двумя массивами, и с помощью этого:

self.sortArrays = function(){
    self.allCourses.sort(function (l, r) {
        return  l.code() < r.code() ;
    });
    self.selectedCourses.sort(function (l, r) {
        return  l.code() < r.code() ;
    });
}

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

self.addCourse = function(course){
    self.selectedCourses.push(course);
    self.allCourses.remove(course);
     self.sortArrays();
};
self.removeCourse = function(course){
    self.allCourses.push(course);
    self.selectedCourses.remove(course);
     self.sortArrays();
};

Ответы [ 3 ]

0 голосов
/ 11 июня 2018

Я бы рассмотрел два подхода.

  1. Держите ваши данные всегда отсортированными.Вместо вызова .sort() найдите правильное место для размещения элемента и вызовите .splice(), чтобы вставить его в нужное место.Это алгоритм O(n), но на практике он должен быть быстрым.
  2. Используйте что-то вроде https://libraries.io/npm/dsjslib, чтобы постоянно поддерживать отсортированную структуру данных.Это делает вставку / удаление операции O(log(n)).Однако каждая операция теперь имеет дополнительную сложность.

Какой из них использовать, будет зависеть от того, будут ли в ваших операциях преобладать усилия вставки / удаления или выполнения списка и его отображения.Мое лучшее предположение состоит в том, что просмотр списка и его отображение имеет большее значение.

Кроме того, следующий вопрос - лучше ли выполнять поиск, просматривая массив или двоичный поиск.Сканирование - это O(n), но ошибки прогнозирования ветвей стоят так дорого, что я видел, что это быстрее, чем двоичный поиск для вставки в списки сотен элементов.

0 голосов
/ 11 июня 2018

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

self.allCoursesSorted = ko.computed(function(){
    return this.allCourses.sort(function (l, r) {
       return  l.code() < r.code() ;
    });
}, this); 

для выбранных курсов, вы можете использовать тот же подход, но с фильтром

self.allCoursesSelected = ko.computed(function(){
    return ko.utils.arrayFilter(this.allCoursesSorted(), 
        function (item) {
            return item.selected === true;
        });
}, this); 
0 голосов
/ 11 июня 2018

При удалении элемента из массива вам никогда не придется выполнять повторную сортировку.

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

Вам нужно будет только определить отсортированную функцию инъекции, поскольку у наблюдаемых массивов уже есть метод remove:

const sorter = (a, b) => a > b ? 1 : a < b ? -1 : 0;

const leftNumbers = ko.observableArray(
  [3,5,1,2].sort(sorter)
);
const rightNumbers = ko.observableArray(
  [4,1,3,5].sort(sorter)
);

// There are many ways to write this function, which you can probable
// find on stack overflow. The destructuring probably makes this slower
// than just re-sorting. I'll leave it up to you to optimize for performance.
const injectSorted = (sorter, arr, nr) => {
  const pos = arr.findIndex(x => sorter(x, nr) > -1);

  if (pos === -1) return arr.concat(nr);
  
  return [
    ...arr.slice(0, pos),
    nr,
    ...arr.slice(pos)
  ];
};

// Notice how we don't need to re-sort
const moveFromTo = (arr1, arr2) => x => {
  arr2(injectSorted(sorter, arr2(), arr1.remove(x)));
};

ko.applyBindings({ leftNumbers, rightNumbers, moveFromTo });
div { display: flex; justify-content: space-around; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<p>Click numbers to move between lists</p>
<div>
  <ul data-bind="foreach: leftNumbers">
    <li data-bind="click: moveFromTo(leftNumbers, rightNumbers), text: $data"></li>
  </ul>
  <ul data-bind="foreach: rightNumbers">
    <li data-bind="click: moveFromTo(rightNumbers, leftNumbers), text: $data"></li>
  </ul>
</div>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...