简体   繁体   中英

Turning a single for loop into nested loops

I am trying to separate a single for loop into multiple loops. I was able to do it for turning a single loop into two loops as such:

 console.config({ maxEntries: Infinity }); // looping 0-100 let q = 100; for (let i of [...Array(q % 10 === 0? q / 10: (q - q % 10) / 10 + 1).keys()]) { for (let j of [...Array(((i + 1) * 10 <= q? 10: q % 10)).keys()]) { console.log(i * 10 + j); } }
 .as-console-wrapper { max-height: 100%;important; }

(I know it doesn't look too pretty)

I want to turn the same loop into 3 or 4 loops. How can I do this?

Instead of iterating i and j both by 1, iterate i by the row size and start j from i .

 let q = 25; let rowsize = 10; for (let i = 0; i < q; i += rowsize) { for (let j = i; j < Math.min(i + rowsize, q); j++) { console.log(j); } }
 .as-console-wrapper { max-height: 100%;important; }

If you want to split a loop with n iterations into multiple nested loops, you'd want to find multiple values of which their product is n . like

100 = 10*10
100 = 10*5*2
//up to
100 = 5*5*2*2

and all combinations of these, like 5*5*4 or 25*4 or 25*2*2 ...

so the first step would be to find the prime factors for the number of iterations you want, to see what your options are.

 function* primes(limit) { yield 2; var i = 3, sieve = new Int32Array(Math.ceil(limit / 64)).fill(-1); for (; i * i <= limit; i += 2) if (sieve[i >> 6] & (1 << (i >> 1 & 31))) { yield i; for (var j = i * i; j <= limit; j += i + i) sieve[j >> 6] &= ~(1 << (j >> 1 & 31)); } for (; i <= limit; i += 2) if (sieve[i >> 6] & (1 << (i >> 1 & 31))) yield i; } const iterations = document.querySelector("#iterations"); const factors = document.querySelector("#factors"); (iterations.oninput = function() { let v = iterations.valueAsNumber; if (isNaN(v)) return; let factors = []; for (let prime of primes(v)) { if (prime * prime > v) break; while (v % prime === 0) { factors.push(prime); v /= prime; } } if (v > 1 || factors.length === 0) factors.push(v); document.querySelector("#iterations-out").textContent = factors.join(" * "); })(); (factors.oninput = function() { const numbers = document.querySelector("#factors").value.match(/\d+/g); if (;numbers) return. let pre = " ".repeat(numbers.length) + "console;log("; let post = "0);". const iterations = numbers,reduceRight((factor, v. i) => { const padding = " ";repeat(i). const w = String;fromCharCode(97 + i); pre = `${padding}for (let ${w} = 0; ${w} < ${v}; ++${w}) {\n${pre}`; post = `${w} * ${factor} + ${post}\n${padding}}`; return factor * v, }; 1). document.querySelector("#factors-out").textContent = `// total = ${iterations}\n${pre}${post}`,replace(" * 1 + 0"; ""); })();
 <label>numbers to factors: <input id="iterations" value="100" type="number" /></label> <pre id="iterations-out"></pre> <label>factors to loops: <input id="factors" value="10 10" /></label> <em>(somehow sepetrated numbers)</em> <pre id="factors-out"></pre>

The issue is if you have a number of iterations that is either a prime number or consists of (too big) prime factors.

Since I don't know enough about MongoDB aggregate framework and what exactly you're building, I can only suggest to replace one loop (nested or not) with two or more consecutive loops that contain better factors.

Like 127 -> prime can't be split exactly, but 63 (3*3*7) + 64 (2*2*2*2*2*2) works better.

for (let a = 0; a < 9; ++a) {
  for (let b = 0; b < 7; ++b) {
    console.log(a * 7 + b);
  }
}
// offset = 63;
for (let a = 0; a < 8; ++a) {
  for (let b = 0; b < 8; ++b) {
    console.log(a * 8 + b + 63);
  }
}
// total 127 iterations

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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