【问题标题】:2 random values from array project来自数组项目的 2 个随机值
【发布时间】:2020-11-02 15:20:43
【问题描述】:

好吧,我必须编写一个计算 2 个随机值的程序。

在程序中,函数中应该有一个列表 (1-9)。从这个列表中我应该得到 2 个随机值(我建议使用 array.splice())。

在选择了 2 个随机值后,程序应该将它们计算(加法)为总值 randomvalue1 + randomvalue2 = totalvalue;

抓住! 在执行 2 个随机值时 cant 的值相同(5+5、3+3、2+2 等是无效)

第二个收获! 随机值不允许连续执行 2 次。 我的意思是程序不应该允许 randomvalue1 连续两次(或更多)等于相同的值(这也适用于 randomvalue2)

到目前为止,我收到了此代码的建议但它不会检查相同的值是否连续出现 x 次

function makeRandom(list) {
 function getRandomIndex() {
     return Math.floor(Math.random() * list.length);
 }

let index1 = getRandomIndex(),
    index2 = getRandomIndex();

while (index1 === index2) index2 = getRandomIndex();

return list[index1] + '+' + list[index2];
}
console.log(makeRandom([1, 2, 3, 4, 5, 6, 7, 8, 9]));

【问题讨论】:

  • 什么不起作用(除了splice 返回一个数组)?
  • @NinaScholz 是的,我真的不知道如何编写代码来满足需求。
  • 如果拼接是你的问题,那么你可以从第一原则开始。将 9 个元素中的一个随机移动到列表的前面(即:将其与第一个位置的任何元素交换),然后将最后 8 个元素中的一个随机移动到第二个位置。数组中的前两个数字将是您选择的两个数字。
  • 不清楚你的“第一次执行代码”和“第二次”是指你需要选择的两个数字,还是我们需要选择两个,然后再选择两个,和这四个数字没有一个可以匹配。

标签: javascript arrays random array-splice


【解决方案1】:

您可以获取索引并循环,直到您获得不同的索引以从数组中获取值。

function makeRandom(list) {
    function getRandomIndex() {
        return Math.floor(Math.random() * list.length);
    }
    
    let index1 = getRandomIndex(),
        index2 = getRandomIndex();

    while (index1 === index2) index2 = getRandomIndex();

    return list[index1] + '+' + list[index2];
}

console.log(makeRandom([1, 2, 3, 4, 5, 6, 7, 8, 9]));

排除一些索引的方法

function makeRandom(list, exclude = []) {
    function getRandomIndex() {
        return Math.floor(Math.random() * list.length);
    }
    function getFreeIndex() {
        let index;

        if (exclude.length >= list.length) return;

        do index = getRandomIndex();
        while (exclude.includes(index))

        exclude.push(index);
        return index;
    }
    
    return getFreeIndex() + '+' + getFreeIndex();
}

console.log(makeRandom([1, 2, 3, 4, 5, 6, 7, 8, 9], [2, 3]));

【讨论】:

  • 这对于 9 个中的 2 个应该没问题。但在一般情况下我不想这样做。找到未使用的值将花费越来越长的时间。
  • 我一直很欣赏你的才华。我认为部分要求是避免重复操作员。您需要在操作时从原始列表中删除使用过的元素。
  • @RandyCasburn:我不知道这是否是一个要求。措辞模棱两可,可能只是为了重申我们不会在选择的对中重复它们。我的回答,就像这个一样,做了相反的假设。
  • @ScottSauyet - 同意歧义 - 哦,等等 - 然后我看到了你的答案!大声笑!
  • 每个返回值前的+号是什么意思?
【解决方案2】:

假设

  1. 你有一个数字数组作为输入

  2. 对makeRandom 的每次调用都应从您的数组中随机选择两个数字并输出总和

  3. 随后对makeRandom 的每次调用都不应使用已使用的任何号码 (id)

     list = [1,1,2,3,4,5];
     // The number 1 could be used twice (but only in different calls to makeRandom)
     // The numbers 2,3,4,5 can only be used once
    
     list = [1,1];
     // Shouldn't work because 1 == 1
    

JS 代码

var list    = [1,2,3,4,5,6,7,8,9];    // Your seed list
var usable  = list.slice(0);          // Copy of your seed list {which we will alter with makeRandom}
function makeRandom(){
    // Check it's possible...
    let counts = {};                                       // Create object to count unique numbers
    for (var i = 0; i < usable.length; i++) {
        counts[usable[i]] = 1 + (counts[usable[i]] || 0);  // Iterate array and fill counts
    }
    if(Object.keys(counts).length < 2){                    // Check there are at least two unique numbers
        console.log("List is too short!");                 // Log error if <2
        return false;                                      // Exit function if <2
    }


    // Get random numbers and output sum...
    let id = Math.floor(Math.random() * usable.length)   // Randomly select an id from usable numbers
    let a  = usable[id];                                 // Set first number
    usable.splice(id, 1);                                // Remove 1st number from usable numbers
    
    let b;
    while(true){                                         // Loop until numbers are different
        id = Math.floor(Math.random() * usable.length);  // Randomly select an id from usable numbers
        b  = usable[id];                                 // Set second number
        if(a !== b)break;                                // Check 1st number isn't the same as the second number
    }
    usable.splice(id, 1);                                // Remove 2nd number from usable numbers
//  console.log(a + " + " + b + " = " + (a+b));          // Log for debugging if required
    return a+b;                                          // Return sum of 1st and 2nd numbers
}

注意:为了便于理解,我已经完整地输入了 while 循环;它可以缩短使用 do...while(...):

    let b;
    do b = list[Math.floor(Math.random() * list.length)];  // Set second number
    while(a==b)                                            // Re-set second number if a == b OR if b was used in the last call to makeRandom

示例

var list    = [1,2,3,4,5,6,7,8,9];
var usable  = list.slice(0);
function makeRandom(){
    let counts = {};
    for (var i = 0; i < usable.length; i++) {
        counts[usable[i]] = 1 + (counts[usable[i]] || 0);
    }
    if(Object.keys(counts).length < 2){
        console.log("List is too short!");
        return false;
    }
    let id = Math.floor(Math.random() * usable.length)
    let a  = usable[id];
    usable.splice(id, 1);
    let b;
    while(true){
        id = Math.floor(Math.random() * usable.length);
        b  = usable[id];
        if(a !== b)break;
    }
    usable.splice(id, 1);
    console.log(a + " + " + b + " = " + (a+b));
    return a+b;
}
// Make several calls to function
makeRandom();
makeRandom();
makeRandom();
makeRandom();
makeRandom();
makeRandom();

// Change the seed lists
var list    = [1,1,1,1,1,9];
var usable  = list.slice(0);

// Make several calls to function
makeRandom();
makeRandom();
makeRandom();

示例输出

__Example 1__
list = [1,2,3,4,5,6,7,8,9]; // Example list used

                // console.log           return
> makeRandom(); // 4 + 2 = 6             6
> makeRandom(); // 1 + 8 = 9             9
> makeRandom(); // 9 + 3 = 12            12
> makeRandom(); // 6 + 7 = 13            13
> makeRandom(); // List is too short!    false
> makeRandom(); // List is too short!    false

__Example 2__
list = [1,1,1,1,1,9]; // Example list used

                // console.log           return
> makeRandom(); // 1 + 9 = 10            10
> makeRandom(); // List is too short!    false
> makeRandom(); // List is too short!    false

替代方案

查看了您的问题的更新...

我不清楚这些数字是否只能使用一次或如果它们不能背靠背使用。

list = [1,2,3,4,5];
                 // Choose from      // Chosen
> makeRandom();  // 1, 2, 3, 4, 5    // 1, 4
> makeRandom();  // 2, 3, 5          // 2, 3
> makeRandom();  // 1, 4, 5          // 1, 5

如果是这样,那么以下内容可能更有用

var list = [1,2,3,4,5,6,7,8,9];    // Your seed list
var used = [];           // Last used pair of numbers
function makeRandom(){
    // Check it's possible...
    let counts = {};                                       // Create object to count unique numbers
    for (var i = 0; i < list.length; i++) {
        counts[list[i]] = 1 + (counts[list[i]] || 0);  // Iterate array and fill counts
    }
    if(Object.keys(counts).length < 4){                    // Check there are at least four unique numbers: any less and we'll end up in an infinite loop on the second call of makeRandom
        console.log("List is too short!");                 // Log error if <2
        return false;                                      // Exit function if <2
    }


    // Get random numbers and output sum...
    let a;
    do a = list[Math.floor(Math.random() * list.length)];  // Set first number
    while(used.includes(a))                                // Reset first number if a was used in the last call to makeRandom
    let b;
    do b = list[Math.floor(Math.random() * list.length)];  // Set second number
    while(a==b || used.includes(b))                        // Re-set second number if a == b OR if b was used in the last call to makeRandom

    used = [a, b];                                         // Set last used numbers
    console.log(a + " + " + b + " = " + (a+b));            // Log for debugging if required
    return a+b;                                            // Return sum of 1st and 2nd numbers
}

// Make several calls to function
makeRandom();
makeRandom();
makeRandom();
makeRandom();
makeRandom();
makeRandom();

// Change the seed lists
var list    = [1,2,3,4];

// Make several calls to function
// Notice with only 4 numbers once the first pair is selected (e.g. 1 & 3) the pattern cycles 1,3 -> 2,4 -> 1,3 -> 2,4
makeRandom();
makeRandom();
makeRandom();

【讨论】:

    【解决方案3】:

    更新答案

    对问题的编辑明确了一些额外的要求,这意味着原始解决方案(如下)不能满足要求。这个版本好像很有用。

    我们引入了一个从固定数组中随机选择的函数,但绝不会选择任何n-最近使用的项目。因此,如果我们使用4 中的n 和[1, 2, 3, 4, 5, 6, 7, 8, 9] 中的arr 调用它,我们将返回一个随机选择一个值的函数,并且在下一次调用时将随机选择另一个值,然后在第三个电话又一个,第四个又一个。这四个之间不会有重复。第五个可能与第一个相同,也可能是不在该列表中的任何其他值。并且第六次调用可能与第二次相同(或者如果在第五轮中没有被重用,则与第一次相同),依此类推。

    const noRepeatRandom = (n, arr) => {
      // TODO: error if n >= arr.length
      let available = [...arr]
      let used = []
      return () => {
        const nextIdx = Math .floor (Math .random() * available .length)
        const next = available [nextIdx]
        used .push (next)
        available .splice (nextIdx, 1)
        if (used .length >= n) {
          available .push (used .shift())
        }
        return next
      }  
    }
    const myRandom = noRepeatRandom (4, [1, 2, 3,4, 5, 6, 7, 8, 9])
    
    // display the results of a bunch of calls to `myRandom()`
    console .log (...Array.from({length: 30}, myRandom))

    我们跟踪两个列表:最近未使用的列表和我们现在不能重复使用的列表(available 和 used。最初我们只是填写 used,但一旦达到 @987654331 @,我们开始从 used 列表中取出最旧的元素并将其添加到 available。

    请注意,应该对n 和数组长度进行错误检查。如果n &gt;= arr.length,这应该会失败。我会把它留作练习。另请注意,如果n == arr.length - 1,您将获得相同arr.length 项目的无限重复循环,因为每次只有一个选项可供选择。


    原答案

    此版本不符合明确要求。它仍然是一种有用的技术,但并不能解决问题。

    我会对数组进行部分改组。下面的代码是Fisher-Yates shuffle 的递归版本,修改为在选择n 元素后停止。它不会修改您的输入数组。

    然后我们通过将2 部分应用到我们的(咖喱)函数来构建pickTwo。

    const partialShuffle = (n) => (xs, i = Math.floor (Math .random () * xs .length)) =>
      n <= 0 || n > xs .length || xs .length == 0
        ? []
        : [xs[i], ... partialShuffle (n - 1) ([... xs .slice (0, i), ... xs .slice (i + 1)])]
    
    const pickTwo = partialShuffle (2)
    
    const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    
    for (let i = 0; i < 5; i ++) {
      console.log(...pickTwo(arr))
    }
    
    console.log('Original not modified:', ...arr)
    .as-console-wrapper {max-height: 100% !important; top: 0}

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-12-27
      • 2023-01-04
      • 1970-01-01
      • 2021-10-31
      • 1970-01-01
      • 2021-11-06
      • 1970-01-01
      相关资源
      最近更新 更多