【问题标题】:How to preserve array keys when removing elements?删除元素时如何保留数组键?
【发布时间】:2016-03-19 15:38:08
【问题描述】:

我想通过随机插入字符来构建一个文本字符串,但是按顺序插入(作为一种效果)。到目前为止,我得到了:

// make a string and an array
var input = "Hello, world!",
    output = [];
// split the string
input = input.split('');

我的想法是这样称呼它

function addAnElement(){
  // check if there are any left
  if(input.length){
     // pick an element at random
     var rand = Math.floor(Math.random() * input.length);
     // remove it, so we don't call it again
     var element = input.splice(rand,1);
     // insert it
     output[rand] = element;
     // use the string returned as new innerHTML, for example 
     return output.join('');
     // repeat until finished
     setTimeout(addAnElement,5);
  }
}

我希望这会返回如下内容:

'e'
'er'
...
'Hel, or!'
...
'Helo, Word!'
... and finally ...
'Hello, World!'

当然,问题在于数组在拼接时会重新索引 - 这会产生乱码。我认为答案必须是将元素链接到它们在input 中的位置,然后将它们原封不动地插入,必要时在返回之前按键排序。 我该怎么做?

【问题讨论】:

  • 您可以保存第二个索引数组并在两个数组中进行拼接,然后从第二个数组获取索引

标签: javascript arrays


【解决方案1】:

这样的事情怎么样:

var input = 'Hello world',
    inputIndexes = [],
    output = [];

for (var i = 0; i < input.length; i++) { 
    inputIndexes[i] = i;
};

function addAnElement() {
    if (inputIndexes.length) {
        var rand = Math.floor(Math.random() * inputIndexes.length);
        var element = inputIndexes.splice(rand, 1);
        output[element] = input[element];
        //console.log(output.join(' '));
        document.getElementById('text').innerHTML = output.join(' ');
        setTimeout(addAnElement, 2000);

    }
}

addAnElement();

http://jsfiddle.net/fg2ybz8j/

【讨论】:

    【解决方案2】:

    您可以通过不使用splice 来避免它。相反,请在使用后清除条目,并记录您已清除的条目。

    例如:

    var entriesLeft = input.length;
    function addAnElement(){
       // pick an element at random, re-picking if we've already
       // picked that one
       var rand;
       do {
          rand = Math.floor(Math.random() * input.length);
       }
       while (!input[rand]);
    
       // get it
       var element = input[rand];
       // clear it, so we don't use it again
       input[rand] = undefined;
       // insert it
       output[rand] = element;
       // repeat until finished
       if (--entriesLeft) {
           setTimeout(addAnElement,5);
       }
       // use the string returned as new innerHTML, for example 
       return output.join('');
    }
    

    当然,对于最后几个字符,选择随机数的循环可能会持续一段时间。如果您担心这一点,您可以创建一个随机索引数组以预先使用。 This question and its answers 地址。

    现场示例:

    var input = "Hello, there!".split("");
    var output = [];
    var entriesLeft = input.length;
    
    function addAnElement() {
      // pick an element at random, re-picking if we've already
      // picked that one
      var rand;
      do {
        rand = Math.floor(Math.random() * input.length);
      }
      while (!input[rand]);
    
      // get it
      var element = input[rand];
      // clear it, so we don't use it again
      input[rand] = undefined;
      // insert it
      output[rand] = element;
      // repeat until finished
      if (--entriesLeft) {
        setTimeout(addAnElement, 5);
      }
      // use the string returned as new innerHTML, for example 
      document.body.innerHTML = output.join('');
    }
    
    addAnElement();

    旁注:请注意我是如何将呼叫转移到setTimeout 之前 returnreturn 退出函数,因此不会有任何对 setTimeout 的调用。也就是说,我对return output.join(''); 的需求感到困惑。除了第一个调用之外,所有调用都是通过计时器机制进行的,它不关心返回值。在实际示例中,我已将该返回值替换为对 document.body.innerHTML 的赋值。


    这里演示了改组索引数组的方法。它使用这个答案中的shuffle 方法,但我并不是说这一定是最好的随机播放方法。

    function shuffle(array) {
      var tmp, current, top = array.length;
      if (top)
        while (--top) {
          current = Math.floor(Math.random() * (top + 1));
          tmp = array[current];
          array[current] = array[top];
          array[top] = tmp;
        }
      return array;
    }
    
    var input = "Hello, there".split("");
    var output = [];
    var indexes = input.map(function(entry, index) {
      return index;
    });
    shuffle(indexes);
    var n = 0;
    
    function addAnElement() {
      // get this index
      var index = indexes[n];
      // get this loop's element
      var element = input[index];
      // insert it
      output[index] = element;
      // repeat until finished
      if (++n < indexes.length) {
        setTimeout(addAnElement, 5);
      }
      // use the string returned as new innerHTML, for example 
      document.body.innerHTML = output.join("");
    }
    
    addAnElement();

    【讨论】:

    • 是的,我不需要返回任何东西来使函数工作,但在我的实际代码中,我正在函数内部进行写入,就像您在上面的 sn-p 中使用 @ 所做的那样987654333@
    • 谢谢。我曾尝试将值设置为 undefined 以保留数组键,但实际字符串远比这长得多,而且一遍又一遍地滚动 1000 面骰子以寻找我们都知道的东西似乎是浪费能量应该是答案。
    • @IsaacLubow:这就是为什么我链接到有关创建随机数组(例如索引)的问题和答案的原因。然后,您只需遍历索引的随机数组,并使用这些索引处的字符。也就是说,对 Chrome 的快速测试表明,现代 JavaScript 引擎将在十分之几毫秒内找到千分之一的数字。当然,在您的目标浏览器/设备上进行测试。
    • 是的,我们可以打乱输入,但是我们如何知道索引 [0] 处的 [随机选择的字符] 在输出字符串中的位置?不会保留密钥。
    • @IsaacLubow:您不会随机输入。您创建第二个索引数组,然后对其进行洗牌。然后使用每个索引循环遍历该数组。
    猜你喜欢
    • 1970-01-01
    • 2020-07-23
    • 1970-01-01
    • 2021-11-04
    • 1970-01-01
    • 2019-05-29
    • 2019-10-03
    • 1970-01-01
    • 2012-08-02
    相关资源
    最近更新 更多