我有一个带有一个名为order的键的对象数组,如下所示:
[{id:"24fin1st",ruler:false,order:1},
{id:"24fin2nd",ruler:false,order:2},
{id:"24fin3rd",ruler:false,order:3},
{id:"24fin4th",ruler:false,order:4}]
假设我们将第4项移至第2项。或第1项到第4项。更新整个密钥订单列表的最有效方法是什么。我正在考虑从原点到目的地获取整个数组,并在该范围内重新编号键,如:
var switchUp = [{
id: "24fin1st",
ruler: false,
order: 1
}, {
id: "24fin2nd",
ruler: false,
order: 2
}, {
id: "24fin3rd",
ruler: false,
order: 3
}, {
id: "24fin4th",
ruler: false,
order: 4
}];
function sortNumber(a, b) {
return a - b;
}
function resort(org, des, arr) {
var move;
if (org > des) {
move = "up";
var range = arr.slice(des - 1, org)
} else {
move = "down";
var range = arr.slice(org - 1, des)
}
range.forEach(function(su, i) {
if (su.order === org) {
su.order = des;
} else {
if (move === "up") {
su.order = su.order + 1;
} else {
su.order = su.order - 1
}
}
})
}
resort(1, 3, switchUp);
switchUp.sort(function(a, b) {
return parseFloat(a.order) - parseFloat(b.order);
});
console.log(switchUp)
我认为这种方式很不错,但不确定它是否是最快的。
答案 0 :(得分:1)
只需重新分配所有order
属性:
array.forEach((o, i) => o.order = i + 1)
答案 1 :(得分:0)
以下是链接列表的实现:
var switchUp = [{
id: "",
ruler: false,
next: "24fin1st",
prev: "24fin4th"
}, {
id: "24fin1st",
ruler: false,
next: "24fin2nd",
prev: ""
}, {
id: "24fin2nd",
ruler: false,
prev: "24fin1st",
next: "24fin3rd"
}, {
id: "24fin3rd",
ruler: false,
prev: "24fin2nd",
next: "24fin4th"
}, {
id: "24fin4th",
ruler: false,
prev: "24fin3rd",
next: ""
}];
var target="";
function check(val) {
return val.id == target;
}
//---code to move "24fin1st" before "24fin3rd"---
//first, find the origin and the destination values
target = "24fin1st";
toMove = switchUp.findIndex(check);
target = "24fin3rd";
newNext = switchUp.findIndex(check);
//the inserts switchUp[toMove] before switchUp[newNext]
target = switchUp[newNext].prev;
newPrev = switchUp.findIndex(check);
target = switchUp[toMove].prev;
oldPrev = switchUp.findIndex(check);
target = switchUp[toMove].next;
oldNext = switchUp.findIndex(check);
switchUp[toMove].next = switchUp[newNext].id;
switchUp[toMove].prev = switchUp[newPrev].id;
switchUp[newPrev].next = switchUp[toMove].id;
switchUp[newNext].prev = switchUp[toMove].id;
switchUp[oldPrev].next = switchUp[oldNext].id;
switchUp[oldNext].prev = switchUp[oldPrev].id;
console.log(switchUp);

为了简化代码,我插入了一个""条目,指向第一个和最后一个条目。通常,这通常使用检测数组开头/结尾的代码进行管理,并采取相应的行动。
如您所见,数组中的实际索引不会更改。改变是什么,"之前"和" next"指针。
现在,如果你需要索引这个数组,那么你可以索引每五个条目,索引[少于五分之一效率不高]。它看起来像是:
var entry = ["24fin1st", "24fin6th", "24fin11th", "24fin16th", "24fin21st"];
var index = [0, 5, 10, 15, 20];
如果您已将第1个条目移动到第13个条目,那么您将在第1个和第13个条目之间将索引减少1。因此,在检查索引数组的值的超高效算法之后,新的索引数组将变为:
index = [0, 4, 9, 15, 20];
注意:如果您在索引中移动一个条目(例如,第15个条目到第11个条目),则需要注意,那么您必须使用switchUp [15] .next或switchUp [15] .prev更新条目数组
注意:如果在某个时刻,索引数组的两个相邻条目变得非常远,那么你必须通过整个数组来重新索引条目和索引数组;但是,这应该非常罕见[我可以根据您的索引距离给出一些概率,以及您可以接受边界的距离以及数组的大小]。
最后,如果您需要导航到第13个条目,那么您将扫描索引数组以获得最接近的值(在本例中为15);然后你导航switchUp.prev两次以进入第13个条目。
注意:如果您在next和prev字段中存储索引而不是标签,那么此算法的效率将提高约20倍。在这种情况下,您将替换
target = switchUp[toMove].prev;
oldPrev = switchUp.findIndex(check);
与
oldPrev = switchUp[toMove].prev;
我们花了整整一周的时间来了解链接列表的不同类型和不同功能,所以我无法在一个答案中解释它们;但是如果有特定的东西你需要帮助,那就问一下。我希望你能在我打字之前知道为什么我想确认这是你想要的东西。
答案 2 :(得分:0)
最后应用的sort
- 交换了两个节点的订单值后 - 可能需要 O(nlogn)时间,而这可以在< em> O(n)两次调用splice
和重新编号循环:
var switchUp = [{
id: "24fin1st",
ruler: false,
order: 1
}, {
id: "24fin2nd",
ruler: false,
order: 2
}, {
id: "24fin3rd",
ruler: false,
order: 3
}, {
id: "24fin4th",
ruler: false,
order: 4
}];
function resort(org, des, arr) {
var first = Math.min(org, des) - 1,
last = Math.max(org, des) - 1;
arr.splice(des-1,0,arr.splice(org-1, 1)[0]);
for (var i = first; i <= last; i++) {
arr[i].order = i + 1;
}
}
resort(3, 1, switchUp);
console.log(switchUp);
请注意splice
将改变突变点后面的所有元素的索引,并且在第二次调用时会再次发生这种情况,这会恢复真正需要的范围右侧元素的原始索引。更改。尽管splice
可以非常有效地执行其任务(因为它是一种内部方法),但是在一个接一个地明确地移动范围内的元素可能更有效(在非常大的数组上):
var switchUp = [{
id: "24fin1st",
ruler: false,
order: 1
}, {
id: "24fin2nd",
ruler: false,
order: 2
}, {
id: "24fin3rd",
ruler: false,
order: 3
}, {
id: "24fin4th",
ruler: false,
order: 4
}];
function resort(org, des, arr) {
var node = arr[org-1],
inc = org < des ? 1 : -1;
for (var i = org-1; i !== des-1; i+=inc) {
arr[i] = arr[i+inc];
arr[i].order = i + 1;
}
node.order = des;
arr[des-1] = node;
}
resort(3, 1, switchUp);
console.log(switchUp);
最后一点:您的函数需要基于1的索引,就像order
值一样。但由于JavaScript使用基于0的索引,因此对于使用您的代码的人来说,这可能是反直觉的。在像slice
这样的标准数组函数期望基于0的索引作为参数的情况下,此自定义函数需要基于1的索引。如果您重新考虑这个选择并使用基于0的索引,那将是一件好事。