【问题标题】:Sized array of random unique numbers随机唯一数字的大小数组
【发布时间】:2018-04-10 00:41:25
【问题描述】:

我想知道获取特定大小的唯一随机数数组的最简洁方法是什么。

我得到这样的随机数:

times(4, () => random(30, 95));

但这并不是唯一的。我可以用uniq 过滤它,但我需要保证数组的长度为 4。我想用 lodash 的方式来做。有什么想法吗?

【问题讨论】:

标签: javascript arrays random unique lodash


【解决方案1】:

我知道这不是“lodash 方式”,但它保证了唯一性,并允许您使用与以前相同的参数。它的扩展性也比需要通过数组进行二分或线性搜索的方法更好,因为set.has() 平均为 O(1),而不是 O(log(n)) 或 O(n)。

function uniqRandom (times, ...args) {
  const set = new Set()

  while (times > 0) {
    const rand = _.random(...args)

    if (!set.has(rand)) {
      set.add(rand)
      times--
    }
  }

  return Array.from(set)
}
 
console.log(uniqRandom(4, 30, 33));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.min.js"></script>

【讨论】:

  • 谢谢你,它可以工作,但我也想出了这样的东西。我一直在寻找 lodash 的方式。
【解决方案2】:

很容易...

const uniqRandomNumbers  = _.sampleSize(_.range(30, 95), 4);
console.log(uniqRandomNumbers);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.min.js"></script>

【讨论】:

  • 这需要一个有限的范围,因为range 创建了巨大的数组。所以我不能做range(0, 50000000)
【解决方案3】:

我从函数式编程的角度解决了这个问题。 refillRandom 是一个递归函数,它检查剩余要生成的项目数并再次调用自身,直到达到所需的项目数。

如果minmax 随机数之间的距离大于所需的唯一项,它也会在不可能生成序列时抛出Error。抛出错误总比永远等待要好。

const generator = (min, offset) => () =>
    Math.floor(Math.random() * offset + min);

const refillRandom = (list, min, max, times) => {
  const offset = max - min,
    num = times - list.length;
  if (times > offset) {
    throw new Error("Imposible to generate it");
  }
  
  const result = _.uniq(_.times(num, generator(min,offset)));
  if (result.length < num) {
    return result.concat(
      refillRandom(list, min, max, num - result.length)
      );
  }
  return result;
}

const r = refillRandom([], 30, 95, 4);

console.log(r);
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.min.js"&gt;&lt;/script&gt;

编辑:我找到了另一个解决方案,我维护了一个生成数字的有序数组并递增生成的数字,以便将其映射到尚未生成的数字。这样我只随机调用指定的times

const randomGenerator = (min, offset, generated, times) => {
  if (!times || !offset) return generated;

  var number = Math.floor(Math.random() * offset + min);
  const len = generated.length;
  for (var i = 0; i < len; i++) {
    if (generated[i] <= number) {
      number++;

    } else {
      generated.splice(i, 0, number);
      return randomGenerator(min, offset - 1, generated, times - 1);
    }
  }
  generated[i] = number;
  return randomGenerator(min, offset - 1, generated, times - 1);

};


const r = randomGenerator(30, 95 - 30, [], 12);

console.log(r);
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.min.js"&gt;&lt;/script&gt;

【讨论】:

  • 除了_.random() 允许通过设置为true 的第三个可选参数返回非整数值,在这种情况下,只要它不为零,距离就无关紧要。
  • 没有说,但我想他需要整数值。我也没有使用 _.random()
  • 非常有趣。是的整数是我需要的。我赞成它类似于循环解决方案。我只是觉得 lodash 有更流畅的东西。非常感谢您的分享!
  • 我觉得lodash没有这种东西,太具体了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多