从0到数字循环并遍历数组(javascript)中的所有数字

时间:2018-08-25 15:39:23

标签: javascript

这里是个主意:

var a = [4, 5, 6];
for (var m = 0; m < a[0]; m++)
  for (var n = 0; n < a[1]; n++)
    for (var p = 0; p < a[2]; p++)
      console.log(`${m} + ${n} + ${p} = ${m+n+p}`);

实时复制:

// This just tells the Stack Snippets in-snippet console not
// to throw away entries once it reaches a max (the default max
// is just the last 50 logs).
console.config({maxEntries: Infinity});

var a = [4, 5, 6];
for (var m = 0; m < a[0]; m++)
  for (var n = 0; n < a[1]; n++)
    for (var p = 0; p < a[2]; p++)
      console.log(`${m} + ${n} + ${p} = ${m+n+p}`);
/* This just makes the console take up the full output area */
.as-console-wrapper {
  max-height: 100% !important;
}

如果数组a具有更多索引,则代码将变得更长。可以使用Array.map或filter或函数来缩短代码吗?

3 个答案:

答案 0 :(得分:1)

将其分解会更容易。首先,您需要为数组的每个元素创建一个序列。

let series = num => Array.from({ length: num + 1 }, (n, i) => i); //creates an array with nums from  0 to num.

这是您问题的第一部分。然后,您需要制作系列的叉积。

基本上对于两个系列[1, 2, 3][1, 2, 3, 4],您将得到一组12个元素:

[2, 3, 4, 5, 3, 4, 5, 6, 4, 5, 6, 7]

为此,您可以这样做:

let crossProduct = (a1, a2) => Array.prototype.concat.call(...a1.map(n1 => a2.map(n2 => n1 + n2)));

现在您要做的就是每个系列都有一个crossProduct

let final = numbers.map(series).reduce(crossProduct);

就在那里:

let numbers = [4, 5, 6];
let series = num => Array.from({ length: num + 1 }, (n, i) => i); 
let crossProduct = (a1, a2) => Array.prototype.concat.call(...a1.map(n1 => a2.map(n2 => n1 + n2)));
let final = numbers.map(series).reduce(crossProduct);
console.log(final);

编辑:如果它是从0到之前的数字(例如4是[0,1,2,3]),则只需在系列函数中使用+ 1

第二次编辑:为您的crossProduct创建的对象更少:

let crossProduct = (a1, a2) => {
    let resultingSet = [];
    for(let i = 0; i < a1.length; i++)
        for(let j = 0; j < a2.length; j++)
            resultingSet.push(a1[i] + a2[j]);
    return resultingSet;
} //only one array is created

如果要避免一直将系列记录存储在内存中,则:

    let numbers = [4, 5, 6];
    let series = function* (num){
        for(let i = 0; i < num; i++){
            yield i;
        }
    }

    let crossProduct = (set, num) => {
       let resultingSet = [];
       for(let i = 0; i < set.length; i++){
           for(let j of series(num)){
               resultingSet.push(set[i] + j);
           }
       }
       return resultingSet;
    }

    let final = numbers.reduce(crossProduct, [0]);
    console.log(final);

答案 1 :(得分:1)

通过使用递归,我们可以在不占用大量内存的情况下做到这一点:

const process = (array, n, numbers) => {
    if (n < array.length) {
        // Not done yet, recurse once for each number at this level
        const max = array[n];
        for (let i = 0; i < max; ++i) {
            process(array, n + 1, [...numbers, i]);
        }
    } else {
        // Done with this level, process the numbers we got
        console.log(`${numbers.join(" + ")} = ${numbers.reduce((s, e) => s + e)}`);
    }
}

process([4, 5, 6], 0, []);

实时复制,并对照您的结果进行核对,以确保上述内容具有相同的作用:

// This just tells the Stack Snippets in-snippet console not
// to throw away entries once it reaches a max (the default max
// is just the last 50 logs).
console.config({maxEntries: Infinity});

function thisSolution() {
  const results = [];
  const process = (array, n, numbers) => {
      if (n < array.length) {
          // Not done yet, recurse once for each number at this level
          const max = array[n];
          for (let i = 0; i < max; ++i) {
              process(array, n + 1, [...numbers, i]);
          }
      } else {
          // Done with this level, process the numbers we got
          const result = numbers.reduce((s, e) => s + e);
          results.push(result);
          console.log(`${numbers.join(" + ")} = ${result}`);
      }
  }

  process([4, 5, 6], 0, []);
  return results;
}

function yourSolution() {
    const results = [];
    var a = [4, 5, 6];
    for (var m = 0; m < a[0]; m++)
      for (var n = 0; n < a[1]; n++)
        for (var p = 0; p < a[2]; p++)
          results.push(m + n + p);
    return results;
}

const thisResult = thisSolution();
const yourResult = yourSolution();
if (thisResult.some((entry, index) => entry !== yourResult[index])) {
    console.log("WRONG");
} else {
    console.log("RIGHT");
}
/* This just makes the console take up the full output area */
.as-console-wrapper {
  max-height: 100% !important;
}

这永远不会深入到堆栈中(确切地说是a.length + 1个堆栈帧,因此在示例情况下为4个)。它建立了多个临时数组(在示例中为145个),它们在a.length个条目中已用完,并在不再需要它们时立即释放它们(在任何给定时间最多保留四个)。这是快速而肮脏的指标:

let maxStack = 0;
let stack = 0;
let totalArrays = 0;
let maxArrays = 0;
let arrays = 0;
// A wrapper for counting stack frames
const process = (...args) => {
    if (++stack > maxStack) {
        maxStack = stack;
    }
    const result = process2(...args);
    --stack;
    return result;
};
const process2 = (array, n, numbers) => {
    if (n < array.length) {
        // Not done yet, recurse once for each number at this level
        const max = array[n];
        for (let i = 0; i < max; ++i) {
            ++totalArrays;
            if (++arrays > maxArrays) {
                maxArrays = arrays;
            }
            process(array, n + 1, [...numbers, i]);
            --arrays;
        }
    } else {
        // Done with this level, process the numbers we got
        //console.log(`${numbers.join(" + ")} = ${numbers.reduce((s, e) => s + e)}`);
    }
}

process([4, 5, 6], 0, []);
++maxArrays;    // To account for the one in the last argument above
++totalArrays;  // "
console.log(`Max stack: ${maxStack}, max arrays: ${maxArrays}, total arrays: ${totalArrays}`);

答案 2 :(得分:0)

另一种不消耗大量内存且相当有效的解决方案是使用一个表示索引值的数组,并在每次迭代时对其进行更新。 首先,创建一个数组,该数组表示每个元素中分别需要运行的迭代次数以分别更新索引,例如,对于该数组[1, 2, 3 ,4 ,5],您将获得: [280, 140, 20, 5, 1]这意味着index [0]将每280次迭代更新,index [1]将每140次迭代更新,依此类推。 就像使用普通的嵌套for循环一样,总共将运行arr [n] * arr [n-1] * arr [n-2] * .... * arr [0]迭代。

var arr = [1, 2, 7, 4, 5];

var indexes = Array.from({length: arr.length}, () => 0);
iterationsPerElement = arr.map((_, i) => arr.slice(i+1).reduce((acc, elem) => acc * elem, 1));

var totalIterations = iterationsPerElement[0] * arr[0];

for(var iteration = 1; iteration <= totalIterations; iteration++) {
    // sum those indexes
    console.log(`sum = ${indexes.reduce((acc, index) => acc + index, 0)}`);

    // update indexes
    for(i = 0; i < indexes.length; i++) {
        if(iteration % iterationsPerElement[i] == 0) {
            indexes[i]++;
            // empty the indexes on the right
            for(var j=i+1; j <indexes.length; j++) {
                indexes[j] = 0;
            }
        }
    }
}