更改排序顺序时更新键值的最短方法是什么

时间:2016-12-13 02:44:16

标签: javascript arrays sorting

我有一个带有一个名为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)

我认为这种方式很不错,但不确定它是否是最快的。

3 个答案:

答案 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的索引,那将是一件好事。