js 数组遍历打印顺序问题

代码:

let str = '12345'
let arr = ['1','2','3','4','5']
let arr1 = ['a','b','c','d','e']
arr.map(item=>{
    return arr1.map(i=>{
        console.log(str.replace(item,i))
    })
})

结果: 希望打印结果按如下顺序每秒输出一条

a2345
b2345
c2345
d2345
e2345
1a345
1b345
1c345
1d345
1e345
12a45
12b45
12c45
12d45
12e45
123a5
123b5
123c5
123d5
123e5
1234a
1234b
1234c
1234d
1234e
阅读 3.8k
5 个回答
let str = '12345'
let arr = ['1', '2', '3', '4', '5']
let arr1 = ['a', 'b', 'c', 'd', 'e']
arr.map((item, index1) => {
    return arr1.map((i, index2) => {
        setTimeout(() => {
            console.log(str.replace(item, i))
        }, (index1 * arr1.length + index2) * 1000)
    })
})
function stepPrintString(nums, letters, i=0, j=0) {
    if(!nums.length || !letters.length || i>nums.length-1) return;
    console.log(nums.slice(0,i) + letters[j] + nums.slice(i+1));
    const isLastLetter = j==letters.length-1;
    setTimeout(() => stepPrintString(nums, letters, isLastLetter ? 1+i : i, isLastLetter ? 0 : 1+j), 1000)
}
stepPrintString('12345','abcde')

我对map的理解是代码顺序执行 但是不等回调完成 改成正常的循环就好了

let str = '12345'
let arr = ['1','2','3','4','5']
let arr1 = ['a','b','c','d','e']
arr.forEach(idx => {
    
    arr1.forEach(v => {
        const newStr = str.replace(idx, v);
         console.log(newStr);
    })

})

看你这个问题的需求应该就是:

  1. 有两个字符串需要进行合并输出,合并的规则为:

    • 从第二个字符串中从第一个字符开始取字符,去替换第一个字符串中的字符
    • 从第 0 个字符开始,每合并一次,第二个字符串中取字符的位置增一
    • 当第二个字符串中的字符都被使用过之后,第一个字符串中被替换的字符位置增一
  2. 每一秒合并一次并输出

代码实现如下:

function loop(arr1, arr2, delta = 1000) {
  //  是否处于循环中
  let looping = true;

  // 合并出所有字符串
  const combined =  arr1.reduce((combined_, _, index) => 
    combined_.concat(arr2.reduce((combined__, char) => 
      combined__.concat([arr1.map((c, i) => i === index ? char : c)]), [])), []);
  let index = 0;

  //  暂停循环
  function toggle() {
    looping = !looping;
    return looping
  }

  let lastPrintTime = Date.now() - delta;

  function print() {
    // 如果是循环中,且上一次执行的时间已经超过 `delta` 指定的时间了,则执行一次
    if (looping && Date.now() - lastPrintTime >= delta) {
      // 打印一次
      console.log(combined[index++].join(''));
      // 更新一次执行时间
      lastPrintTime = Date.now();
    }
    // 如果还未执行完成
    if (index < combined.length) {
      // 循环
      requestAnimationFrame(print);
    }
  }

  print();
  
  return toggle;  
}

使用方式:

const toggle = loop(['1', '2', '3', '4', '5'], ['a', 'b', 'c', 'd', 'e']);
// 在任何时候,可以执行 `toggle()` 暂停,再一次执行则继续

如果 arr1arr2 数据量多大的话,可以不提前全部生成(提前全部生成的话,在打印的时候,就不会出现需要花费太多时间计算的问题了):

function loop(arr1, arr2, delta = 1000) {
  //  是否处于循环中
  let looping = true;
  const str = arr1.join('');

  const index = [0, 0];

  //  暂停循环
  function toggle() {
    looping = !looping;
    return looping
  }

  let lastPrintTime = Date.now() - delta;

  function print() {
    // 如果是循环中,且上一次执行的时间已经超过 `delta` 指定的时间了,则执行一次
    if (looping && Date.now() - lastPrintTime >= delta) {
      // 打印一次
      console.log(str.replace(arr1[index[0]], arr2[index[1]]));
      // 更新一次执行时间
      lastPrintTime = Date.now();

      if (index[1] === arr2.length - 1) {
        index[0] += 1;
        index[1] = 0;
      } else {
        index[1] += 1;
      }
    }
    // 如果还未执行完成
    if (index[0] < arr1.length) {
      // 循环
      requestAnimationFrame(print);
    }
  }

  print();
  
  return toggle;  
}

因为返回了一个 toggle 函数,所以,如果还需要有一些信息可以被跟踪的话,可以往这个函数上面挂,比如我现在想通过 toggle 随时查看当前的循环进度,可以像下在这样实现:

function loop(arr1, arr2, delta = 1000) {
  //  是否处于循环中
  let looping = true;
  const str = arr1.join('');

  const index = [0, 0];

  //  暂停循环
  function toggle() {
    looping = !looping;
    return looping
  }

  Object.defineProperty(toggle, 'index', {
    get () {
      return index;
    }
  })

  let lastPrintTime = Date.now() - delta;

  function print() {
    // 如果是循环中,且上一次执行的时间已经超过 `delta` 指定的时间了,则执行一次
    if (looping && Date.now() - lastPrintTime >= delta) {
      // 打印一次
      console.log(str.replace(arr1[index[0]], arr2[index[1]]));
      // 更新一次执行时间
      lastPrintTime = Date.now();

      if (index[1] === arr2.length - 1) {
        index[0] += 1;
        index[1] = 0;
      } else {
        index[1] += 1;
      }
    }
    // 如果还未执行完成
    if (index[0] < arr1.length) {
      // 循环
      requestAnimationFrame(print);
    }
  }

  print();
  
  return toggle;  
}

此时,就可以像下面这样得到最新的进度了:

const toggle = loop(['1', '2', '3', '4', '5'], ['a', 'b', 'c', 'd', 'e'])

// 在任何时候,可以通过下面这样得到 `index`
toggle.index
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题