我有两个可观察的数组,我需要从第一个删除元素并推送到第二个,反之亦然。但是当我这样做时,字母排序就搞砸了。
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();
};
答案 0 :(得分:2)
从数组中删除项目时,您将永远不必进行重新排序。
您可以使用排序定义插入项目,而不是推送并重新排序。
您只需要定义已排序的inject函数,因为knockout可观察数组已经有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>
答案 1 :(得分:2)
我会考虑两种方法。
.sort()
,而是搜索放置元素的正确位置,然后调用.splice()
将其插入正确的位置。这是一个O(n)
算法,但在实践中应该很快。O(log(n))
操作。但是现在每个操作都有额外的复杂性。使用哪一个取决于您的操作是由插入/删除工作,还是通过运行列表并显示它来控制。我最好的猜测是,遍历列表并显示它更重要。
此外,下一个问题是通过扫描数组或二进制搜索来进行搜索是否更好。扫描是O(n)
但是分支预测错误的成本太高,以至于我发现它比二进制搜索更快地插入到数百个元素的列表中。
答案 2 :(得分:2)
使用knockout,你也可以根据你的observable数组创建计算器,所以你总是会有排序的数组
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);