简体   繁体   English

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

[英]Loop from 0 to a number and loop through all numbers in array (javascript)

Here is the idea: 这里是想法:

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}`);

Live Copy: 实时复制:

 // 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; } 

The code would get longer if the array a has more indexes. 如果数组a具有更多索引,则代码将变得更长。 Could the code be shorten using Array.map or filter or a function? 是否可以使用Array.map或filter或函数来缩短代码?

It's easier if you break it down. 如果将其分解,会更容易。 First, you need to create a series per every element of your array. 首先,您需要为数组的每个元素创建一个序列。

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

That's the first part of your question. 那是你问题的第一部分。 Then you need to do a cross product of your series. 然后,您需要制作系列的叉积。

Basically for two series [1, 2, 3] and [1, 2, 3, 4] you'll end up with a set of 12 elements: 基本上,对于两个系列[1, 2, 3][1, 2, 3, 4]您将得到一组12个元素:

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

And for that you could do: 为此,您可以执行以下操作:

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

Now all you need to do is have a crossProduct for every series. 现在,您需要做的就是每个系列都有一个crossProduct

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

And there you have it: 那里有:

 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); 

Edit: If it's from 0 to the number before (eg 4 is [0, 1, 2, 3]) then just take the + 1 in the series function. 编辑:如果它是从0到之前的数字(例如4是[0,1,2,3]),则只需在系列函数中加上+ 1

2nd Edit: Less objects created for your crossProduct : 第二编辑:为您的crossProduct创建的对象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

And if you want to avoid having the series on memory all the time: 而且,如果您要避免一直将序列存储在内存中,请执行以下操作:

  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); 

We can do this without taking up massive amounts of memory, and fairly simply, by using recursion: 通过使用递归,我们可以在不占用大量内存的情况下轻松地做到这一点:

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, []);

Live Copy, with cross-checking against your results to ensure the above does the same thing: 实时复制,通过对您的结果进行交叉检查来确保上述操作具有相同的作用:

 // 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; } 

This never goes deep into the stack ( a.length + 1 stack frames, to be precise, so four in the example case). 这永远不会深入到堆栈中(准确地说,是a.length + 1个堆栈帧,因此在示例中为4个)。 It builds up a number of temporary arrays (145 in the example case) that max out at a.length entries, releasing them as soon as they aren't needed anymore (a max of four are retained at any given time). 它建立了许多临时数组(在本例中为145个),这些数组在a.length个条目中达到最大值,并在不再需要它们时立即释放它们(在任何给定时间最多保留四个)。 Here's the quick and dirty metrics on that: 这是快速而肮脏的指标:

 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}`); 

Another solution that doesn't consume alot of memory and fairly efficient is by using an array that represnt the value of the indexes and update it each iteration. 另一种不消耗大量内存且相当高效的解决方案是使用表示索引值并在每次迭代中对其进行更新的数组。 first you create an array that represent in each element the amount of iterations you need to run in order to update the indexes respectively for example for this array [1, 2, 3 ,4 ,5] you will get: [280, 140, 20, 5, 1] this means that index[0] will be updated each 280 iterations, index[1] will be updated each 140 iterations and so on.. totally you will run arr[n] * arr[n-1] * arr[n-2] * .... * arr[0] iterations as you did with ordinary nested for loop. 首先,您创建一个数组,该数组表示每个元素中分别需要运行的迭代次数以分别更新索引,例如,对于此数组[1, 2, 3 ,4 ,5]您将得到: [280, 140, 20, 5, 1]这意味着index [0]将每280次迭代更新,index [1]将每140次迭代更新,依此类推..总共,您将运行arr [n] * arr [n-1] * arr [n-2] * .... * arr [0]迭代,就像使用普通的嵌套for循环所做的那样。

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;
            }
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM