【问题标题】:JS: Random String without Repeating Same String TwiceJS:随机字符串,不重复相同的字符串两次
【发布时间】:2015-05-24 00:41:40
【问题描述】:

我正在想办法用纯 JS 从数组中拉出一个随机字符串,而同一字符串不会连续出现两次。

我使用随机数 (random number) 使用随机数的索引从 randomMsg 中提取随机字符串,然后将其存储在 currentMsg 中。

点击后,我将使用新的随机字符串重新定义currentMsg。然后我使用if/else 语句来查看我们的prevMsg 是否等于currentMsg,如果是(不是第一次点击),我正在使用另一个if /else 语句来增加或减少我们的索引,因此它返回一个唯一的字符串 (anotherMsg) 到我们的 HTML 并将 prevMsg var 设置为该字符串。

否则,它将 currentMsg 返回到我们的 HTML,并将 prevMsg 设置为等于 currentMsg

功能如下:

(function message() {
    var ranNumber = Math.floor((Math.random() * 5) + 0);
    var randomMsg = [
      "string one",
      "string two",
      "string three",
      "string four",
      "string five"
    ];

    var currentMsg = randomMsg[Math.floor((Math.random() * 5) + 0)];
    var prevMsg = "";

    document.getElementById("intro").innerHTML = currentMsg;

    document.getElementById("intro").onclick = function() {
        var ranNum = Math.floor((Math.random() * 5) + 0);
        currentMsg = randomMsg[ranNum];
        if(prevMsg == currentMsg) {
            var anotherMsg = "";
            if(ranNum >= 0 && ranNum < 4) {
                anotherMsg = randomMsg[ranNum + 1];
            }
            else {
                anotherMsg = randomMsg[ranNum - 1];
            }
            document.getElementById("intro").innerHTML = anotherMsg;
            prevMsg = anotherMsg; // set prevMsg to anotherMsg
        } else {
            document.getElementById("intro").innerHTML = currentMsg;
            prevMsg = currentMsg; // set prevMsg to currentMsg
        };
    };
})();

我还设置了JSFiddle here

虽然它有效,但我现在很想知道是否有更优雅的方法来编写这样的函数。另外我要替换整个字符串,是只替换单词(一、二、三等)更好还是一点都不重要?

感谢任何帮助。提前致谢!

【问题讨论】:

  • 因为“它有效,”并且您的问题需要审核,我建议您在Code Review 上提问,而不是在Stack Overflow 上提问。跨度>

标签: javascript string random


【解决方案1】:

出于可读性通用的原因,数组应该位于外部 函数 >:

var msg = [
    "string one",
    "string two",
    "string three",
    "string for",
    "string five",
    "string six" /* add as many values as you want */
];

返回随机数不是当前随机数的函数:

function randWithout(n, arr) {
    var res = [];
    for (var i = 0; i < arr.length; i += 1) {
        if (i !== n) {
            res.push(i);
        }
    }
    return res[Math.floor(Math.random() * (arr.length - 1))];
}

Arr 必须是函数的参数,因为需要数组的 length。还有一个返回随机数的函数:

function randNumber(arr) {
    var rand = Math.floor(Math.random() * arr.length);
    return rand;
}

最后一个函数:

(function message() {
    var intro = document.getElementById("intro");
    var currNumber = randNumber(msg);
    intro.innerHTML = msg[currNumber];
    var clickNumber = randWithout(currNumber, msg);
    intro.onclick = function () {
        intro.innerHTML = msg[clickNumber];
        clickNumber = randWithout(clickNumber, msg);
    }
})()

简单可读

Demo

【讨论】:

  • 谢谢你。非常简单易懂。我不知道return res[Math.floor(Math.random() * (arr.length - 1))]; 在做什么——你能解释一下吗?
  • function randWithout 中,您将数组中的所有索引(此处为 msg),除了 当前数字 中的索引推送到结果数组。长度为arr.length - 1。这里 msg 数组的长度为 6,结果数组的长度必须为 5。例如 res = [0, 1, 3, 4, 5]。这里的当前数字是 2。我们不希望这个数字紧随其后。 Math.floor(Math.random() * 5) 来自 (0, 1, 2, 3, 4) 的随机数。 res[Math.floor(Math.random() * (arr.length - 1))] 例如 res[3] 来自 [0, 1, 3, 4, 5] 4。
【解决方案2】:

不是从数组中随机拉出一个字符串,而是打乱数组并按顺序拉出字符串。

randomMsg.sort(function(){return Math.random()-0.5}); // shuffle

如果您想保持randomMsg 的原始顺序,只需将.slice() 放入另一个数组中:

var shuffedMsg = randomMsg.slice().sort(function(){return Math.random()-0.5});

就像洗一副牌一样,您可以多次洗牌以进一步混合。但是像上面的例子一样调用.sort() 会很乏味。所以将它包装在一个函数中:

function shuffle (arr) {
    return arr..sort(function(){return Math.random()-0.5});
}

var shuffledMsg = shuffle(shuffle(shuffle(randomMsg.slice())));

【讨论】:

    【解决方案3】:

    我取消了另一个消息,一个 if 子句,并使用了三元运算符:

    (function message() {
        var currentMsg, prevMsg;
        var ranNumber = Math.floor((Math.random() * 5) + 0);
        var randomMsg = [
          "string one",
          "string two",
          "string three",
          "string four",
          "string five"
        ];
        prevMsg = (prevMsg) ? prevMsg : "";
        var currentMsg = randomMsg[ranNumber];
        document.getElementById("intro").innerHTML = currentMsg;
    
        document.getElementById("intro").onclick = function() {
            var ranNum = Math.floor((Math.random() * 5) + 0);
            currentMsg = randomMsg[ranNum];
            if(prevMsg === currentMsg) {
                ranNum = (ranNum === 4) ? 0 : ranNum++;
                currentMsg = randomMsg[ranNumber];
            } 
        document.getElementById("intro").innerHTML = currentMsg;
        prevMsg = currentMsg;       
    };
    })();
    

    【讨论】:

      【解决方案4】:

      我更喜欢可读性更高的方法。

      (function message() {
          var introElem = document.getElementById("intro");
          var randomMessages = [
            "string one",
            "string two",
            "string three",
            "string four",
            "string five"
          ];
          var randomMessagesLength = randomMessages.length;
      
          introElem.innerHTML = getRandomMessage(introElem);
          introElem.onclick = function() {
              introElem.innerHTML = getRandomMessage(introElem);
          };
      
          function getRandomMessage(elem) {
              var isNewRandMessage = false;
              var randMessage = "";
              do {
                  randNumber = Math.floor(Math.random() * randomMessagesLength);
                  randMessage = randomMessages[randNumber];
                  if (elem.innerHTML != randMessage) {
                      isNewRandMessage = true;
                  }
              } while (!isNewRandMessage);
      
              return randMessage;
          }
      })();
      

      【讨论】:

        【解决方案5】:

        以下代码非常简单,但可能会不断迭代,特别是在消息数量较少的情况下。如果没有至少两条消息,则会出现无限循环。

        var messages = ["string one", "string two", "string three", "string four", "string five"];
        var i = -1,
            intro = document.getElementById("intro");
        (intro.onclick = function() {
          while( i == (i = Math.floor((Math.random() * messages.length))) );
          intro.textContent = messages[i];
        })();
        &lt;h1 id="intro"&gt;&lt;/h1&gt;

        为避免这些问题,最好使用以下方法,即使它不那么简单:

        var messages = ["string one", "string two", "string three", "string four", "string five"];
        var i = Math.floor((Math.random() * messages.length)),
            intro = document.getElementById("intro");
        (intro.onclick = function() {
          intro.textContent = messages[i];
          var rand = Math.floor((Math.random() * (messages.length-1)));
          i = rand + (rand >= i);
        })();
        &lt;h1 id="intro"&gt;&lt;/h1&gt;

        【讨论】:

          【解决方案6】:

          添加了另一个 tmpMsg,点击时将消息移动到 tmpMsg,在下一次迭代时合并回 randomMsg 并将最新显示的消息移动到 tmpMsg。

              (function message() {
              var randomMsg = [
                  "string one",
                  "string two",
                  "string three",
                  "string four",
                  "string five"
              ];
          
              var random = function() {
                  return Math.floor((Math.random() * (randomMsg.length)) + 0);
              }
          
              var tmpMsg;
              var ranNumber = random();
          
              var currentMsg = randomMsg[ranNumber];
          
              tmpMsg = randomMsg.splice(ranNumber, 1)[0];
          
              document.getElementById("intro").innerHTML = currentMsg;
          
              document.getElementById("intro").onclick = function() {
                  ranNumber = random();
                  currentMsg = randomMsg[ranNumber];
                  document.getElementById("intro").innerHTML = currentMsg;
                  randomMsg.push(tmpMsg);
                  tmpMsg = randomMsg.splice(ranNumber, 1)[0];
          
                  if (randomMsg.length === 0) {
                      randomMsg = tmpMsg;
                      tmpMsg = [];
                  }
          
              };
          })();
          

          【讨论】:

            猜你喜欢
            • 2010-11-10
            • 2020-05-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多