【问题标题】:Javascript - how to pick random elements from an array in order?Javascript - 如何按顺序从数组中选择随机元素?
【发布时间】:2016-04-24 00:34:27
【问题描述】:

我有一个数组

var numbers = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18"];

并试图从中获取随机项目,所以:

console.log(_.sample(numbers, 5));

这将以随机顺序从数组中给我 5 个随机数(字符串),例如:

"17", "2", "3", "18", "10"

如何获得排序列表或随机项目,例如?

"2", "3", "10", "17", "18"

_.sample 可能不是这里的最佳选择。我正在尝试从给定数组中获取随机项,并从数组的左到右拾取这些项。

如何在 javascritp 中做到这一点?

谢谢。

编辑:我有一个字符串数组,而不是数字,所以我无法对随机挑选的项目进行排序。

EDIT2: 为避免混淆,数组中有单词(= 字符串),我使用数字作为字符串来更轻松地展示我想要实现的目标。 (抱歉可能造成混淆)

【问题讨论】:

  • 包含数字的字符串也可以很容易地按数字排序。还是数字字符串只是一个例子?
  • 在上面的示例中,我在那里使用了数字,因为更容易演示我想要做什么 - 数组中是字符串(单词)。

标签: javascript jquery arrays random


【解决方案1】:

可以使用Array.prototype.sort对返回的数组进行排序:

即。

_.sample(numbers, 5).sort(function(a, b) { return parseInt(a, 10) - parseInt(b, 10) })

更好的随机数是:

var randomChoice = numbers[~~(Math.random() * numbers.length)]

注意~~ 在此上下文中执行与 Math.floor() 相同的操作。它们可以互换。

大家一起:

var numbers = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18"];

var randomSample = []

for(var i=0; i < 5; i++) {
   var randomChoice = numbers[~~(Math.random() * numbers.length)]
   randomSample.push(randomChoice)
}

var sortedRandomSample = randomSample.sort(function(a, b) { return parseInt(a, 10) - parseInt(b, 10) })

演示:https://jsbin.com/zosizefaga/edit?html,js,console,output

【讨论】:

  • 那个 for 循环可能会选择五次相同的元素。
  • 你是对的。这就是随机选择的本质。 @nnnnnn。
  • 但这不是 OP 想要的。他们显然想要随机选择五个不同的元素。
  • @nnnnnn 如果 OP 要求,可以稍作更改以从 numbers 数组中删除所选元素,以确保所有选择都不同。
  • 注意:如果您需要在代码中添加注释,它的可读性不够:D,我会选择 Math.floor 而不是太聪明
【解决方案2】:

这是一个不对原始订单做任何假设的解决方案。这个想法是在原始数组中查找元素的位置并按此排序。但是,这是假设每个元素都是唯一的。

sample.sort(function(a, b) {
    return numbers.indexOf(a) - numbers.indexOf(b);
});

对于大型数组,这也会很慢。

【讨论】:

  • 我认为复杂度是 O(n² log n)。如果你想改进它,你可以创建一个使用字符串作为键和索引作为值的哈希。如果您在排序之前执行此操作并使用散列而不是indexOf,则会再次使其变为 O(n log n)。
【解决方案3】:

为什么不实现自己的sample方法,调用_.sample后调用sort方法?

【讨论】:

  • 这似乎更像是一个评论而不是一个答案。
【解决方案4】:

我能想到的最简单的方法如下:

var randomSample = _.sample(numbers.map(function(v,i){ return i; }), 5)
                    .sort(function(a,b){ return a-b; })
                    .map(function(v){ return numbers[v]; });

也就是说,创建一个临时数组来保存原始数组的索引,即只有数字0numbers.length - 1):

var indices = numbers.map(function(v,i){ return i; })

那个数组中随机抽取一个样本:

var sampleIndices = _.sample(indices, 5)

对样本进行排序:

sampleIndices.sort(function(a,b){ return a-b; })

然后使用排序的、随机选择的索引从原始数组中获取值:

var randomSample = sampleIndices.map(function(v){ return numbers[v]; });

如我的答案开头所示,您可以在一行中完成所有操作,而无需使用 indicessampleIndices 变量。虽然如果您要定期从同一个 numbers 数组中抽取样本,那么保留 indices 变量以节省每次重新构建它可能是有意义的,尤其是在原始数组非常大的情况下。

无论原始数组中的值是什么类型,这都会起作用,因为一旦选择了随机索引,这些值就会在最后被选择出来。

【讨论】:

    【解决方案5】:

    试试这个:

    function random(array, elements) {
       return array.concat().sort(function() {
         if (Math.random() < 0.5) {
           return -1;
         } else {
           return 1;
         }
       }).slice(0, elements).sort(
         function(a, b) {
           return a - b
         });
    }
    

    这是小提琴:

    JSFiddle

    【讨论】:

    • 但是...这会修改原始数组,并以随机顺序返回选定的元素。 OP 不想做这两件事。
    • 它不会修改原始数组,检查小提琴。是的,它返回了一个随机顺序数组,我的错误。
    • 确实修改了原始数组。添加console.log(numbers);之后你调用你的函数,你会看到。
    【解决方案6】:

    这是一个没有排序的提案,它使用一个辅助数组random 来表示选定的项目。

    首先得到一个空数组,然后用true填充,直到填充count元素,然后用随机选择的位置过滤原始数组。

    此解决方案适用于给定数组的任何内容,无需使用 indexOf 进行排序或查找。

    function getSortedRandom(array, count) {
        var random = array.map(function () { return false; }),
            r;
    
        while (count) {
            r = Math.floor(Math.random() * array.length);
            if (!random[r]) {
                random[r] = true;
                count--;
            }
        }
        return array.filter(function (_, i) {
            return random[i];
        });
    }
    
    var random = getSortedRandom(["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18"], 5);
    
    document.write('<pre>' + JSON.stringify(random, 0, 4) + '</pre>');

    【讨论】:

      【解决方案7】:

      从 lodash 4.0.0 开始,您可以将 _.sampleSize 函数与 sort 结合使用:

      var numbers = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18"];
      
      var randomSample = _.sampleSize(numbers, 5).sort();
      
      console.log(randomSample);
      &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.14.1/lodash.min.js"&gt;&lt;/script&gt;

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-09-19
        • 2022-12-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多