【问题标题】:JavaScript ensure all numbers are unique and if not plus one (or more)JavaScript 确保所有数字都是唯一的,如果不加一(或更多)
【发布时间】:2017-11-01 23:27:48
【问题描述】:

我正在尝试在 d3 图表上放置一些标签。

我有一个 DATA 对象,每个对象都有一个 DATA.rowOffset 值。基本上我的代码计算 DATA.rowOffset 并将其设置为:d.rowOffset = Math.floor(d.total/heightSquares); 但有时 rowOffset 是相同的,因此标签呈现在彼此之上。

我需要循环浏览此 DATA 并检查重复项,然后只需 +1 任何重复项。

我尝试了一种方法,查看之前的.rowOffset,然后在当前的rowOffset 上加1,但是如果有超过2 个重复项,这将不起作用。

我确信有更简单的方法......也许。

编辑:这是我主要尝试的一些代码if (d.rowOffset === DATA[i-1].rowOffset) d.rowOffset++;,因此它会检查前一行偏移量。我想我需要循环遍历所有数据,如果发现重复则重新开始循环。

DATA.forEach(function(d, i) {
      d.amt = +d.amt;

      d.units = Math.floor(d.amt / squareValue);

      sumTotal = sumTotal + d.units;
      d.total = sumTotal;



      d.rowOffset = Math.floor(d.total / heightSquares);

      if (i > 0) {
        console.log(DATA[i - 1].rowOffset);
        if (d.rowOffset === DATA[i - 1].rowOffset) d.rowOffset++;
      }

【问题讨论】:

  • 如果你有[2, 2, 2]呢?你期待[2, 3, 3] 还是[2, 3, 4]
  • [2, 3, 4] 所以所有值都是唯一的,如果标签试图在同一行上,它们只会堆叠在彼此下方。谢谢
  • 你能显示你尝试的方法的代码吗?
  • @phocks 好的,这实际上为您的问题增加了一层复杂性,因为每个增加的副本都可能成为另一个数字的副本,并且必须考虑到这一点。我添加了一种可能的解决方案,希望对您有所帮助。

标签: javascript algorithm d3.js duplicates


【解决方案1】:

这是您可以采取的一种方法。

您初始化一个空的Set 数据结构来跟踪您迄今为止遇到的唯一值。您遍历数组并为每个值执行以下操作:

  • 如果之前遇到过该值,则将其递增,直到与之前遇到的任何值都不匹配
  • 更新遇到的值以包含这个新值
  • 用新值替换旧值

这是代码中的样子:

function incrementDups(arr) {
  // a set of encountered unique values
  const encounters = new Set();

  // increment each duplicate until it has no duplicates
  return arr.map(num => {
    while (encounters.has(num)) {
      num += 1;
    }
    encounters.add(num);
    return num;
  });
}

console.log(
  incrementDups(
    [1, 2, 2, 3, 2, 2, 4] // [1, 2, 3, 4, 5, 6, 7]
  )
);

console.log(
  incrementDups(
    [1, 1, 1, 1, 1, 1, 1] // [1, 2, 3, 4, 5, 6, 7]
  )
);

console.log(
  incrementDups(
    [1, 99, 55, 4, 55, 2] // [1, 99, 55, 4, 56, 2]
  )
);

上述解决方案具有二次最坏情况时间复杂度。产生这种情况的输入是一个仅包含重复项的数组,例如[1, 1, 1, 1],其中嵌套while 循环的最后一次迭代将运行N 增量。尽管如此,平均而言,这个算法应该表现得相当不错。

可以通过使用更多空间来记住某个副本的最后一个增量值并将其用作增量的起始值而不是数字本身来进行进一步优化。

现在,上面的代码实际上做了相当多的重复。如果我们有[2, 2, 2, ...],对于每个2,我们将从234 等开始递增,尽管从技术上讲,以前的2 已经为我们完成了工作。理想情况下,我们希望第一个22 开始计数,第二个23 开始计数,等等。这对于连续值的大型数组特别有用。例如,如果我们有[1, 2, ... 99, ... 2, 2, 2, 2 /* 100 times */],使用第一个算法,每个2 将从2 计数到99,加上下一个唯一值的增量。另一方面,使用这种新方法,只有第一个 2 会这样做。下一个2 只会将99 增加到100,下一个100 会增加到101,依此类推。如果像以前一样给我们一个仅包含重复项的数组 [1, 1, 1 ...],那么每个 1 现在只需要增加一次,而不是遍历整个范围。

这将时间复杂度收紧到O(N*max(array)),它仍然是二次的,但只取决于值的范围,而不是像以前那样重复的数量。它还针对您的特定情况进行了更优化,因为您会期望一组值彼此接近的低数字。

要跟踪此信息,我们可以使用一个数字的Map 来表示它递增到的最新唯一值。

function incrementDups(arr) {
  // a set of encountered unique values
  const encounters = new Set();

  // a map of the last unique non-duplicate for each value
  const lastNonDup = new Map();

  // increment each duplicate until it has no duplicates
  return arr.map(num => {
    let updatedNum = lastNonDup.has(num) ? lastNonDup.get(num) : num;
    while (encounters.has(updatedNum)) {
      updatedNum += 1;
    }
    encounters.add(updatedNum);
    lastNonDup.set(num, updatedNum);
    return updatedNum;
  });
}

console.log(
  incrementDups(
    [1, 2, 2, 3, 2, 2, 4] // [1, 2, 3, 4, 5, 6, 7]
  )
);

console.log(
  incrementDups(
    [1, 1, 1, 1, 1, 1, 1] // [1, 2, 3, 4, 5, 6, 7]
  )
);

console.log(
  incrementDups(
    [1, 99, 55, 4, 55, 2] // [1, 99, 55, 4, 56, 2]
  )
);

【讨论】:

    猜你喜欢
    • 2023-02-21
    • 2011-04-30
    • 2022-06-20
    • 1970-01-01
    • 2013-12-26
    • 2022-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多