I make a "genetic calculator", it must "cross" each letter of each element gens[[],[]] with another element.

There is a code that creates code that then executes:

 for (var u in gens) { var estr = ""; for (var i = 0; i < gens[u].length; i++) { var na = gens[u][i].charAt(0).toUpperCase(); estr += 'for(var ' + na + '=0;' + na + '<=1;' + na + '++){\n'; } estr += 'var res=cross(['; for (var i = 0; i < gens[u].length; i++) { var na = gens[u][i].charAt(0).toUpperCase(); estr += 'gens[' + u + '][' + i + '].charAt(' + na + '),'; } estr = estr.substring(0, estr.length - 1); estr += ']);\nif(!test(gomets[' + u + '],res,true)){gomets[' + u + '].push(res);}\n'; for (var i = 0; i < gens[u].length; i++) { estr += '}\n'; } alert(estr); //eval(estr); } 

The bottom line is that he with gens=[['AA','Bb'],['aa','BB']]; creates the code first:

 for (var A = 0; A <= 1; A++) { for (var B = 0; B <= 1; B++) { var res = cross([gens[0][0].charAt(A), gens[0][1].charAt(B)]); if (!test(gomets[0], res, true)) { gomets[0].push(res); } } } 

And then

 for (var A = 0; A <= 1; A++) { for (var B = 0; B <= 1; B++) { var res = cross([gens[1][0].charAt(A), gens[1][1].charAt(B)]); if (!test(gomets[1], res, true)) { gomets[1].push(res); } } } 

The point is that the code creates as many nested loops as there are elements in gens[u] , for example, gens[0] .

Each cycle should count from 0 to 1 (so the length of the string is "AA", "bb" and so on 2 characters) and record the result in a variable whose name corresponds to gens[u].[Π½ΠΎΠΌΠ΅Ρ€ элСмСнта/Ρ†ΠΈΠΊΠ»Π°].charAt(0); in the body of the nested loop, the function is executed, the array with the elements gens[u][0].charAt(имя счётчика Ρ†ΠΈΠΊΠ»Π°) must fall into its parameters, since the index ranges from 0 to 1, then the loop takes each letter. I thought about the algorithm, I couldn’t think of anything better, because the number of elements in gens[u] fluctuates and all letters of all elements need to be passed functions in turn, and for this you need as many cycles as there are elements in gens[u] .

Actually the question is: can this be organized without eval'a ?

ps If something is not clear in the question, ask, I will explain.

UPD: for gens=[['AA','Bb','Cc'],['aa','BB','Cc']]; generated code:

 for (var A = 0; A <= 1; A++) { for (var B = 0; B <= 1; B++) { for (var C = 0; C <= 1; C++) { var res = cross([gens[0][0].charAt(A), gens[0][1].charAt(B), gens[0][2].charAt(C)]); if (!test(gomets[0], res, true)) { gomets[0].push(res); } } } } 
  • 95% sure you can - Specter
  • I have been thinking about this for 3 days, but (maybe because I study at school and self-taught) I can’t think of such a code for languages ​​without eval, for example, pascal (of course, it is a thing of the past IMHO), ie for the compiler and not for interpreters - Rules
  • maybe I did not quite understand the question correctly, but try to turn your gaze towards recursion - FLK
  • Please explain in more detail. I misunderstand what recursion is when it refers to itself? If I know the wrong way, don't swear, but better explain to the newbie :) - Rules
  • eight
    To understand recursion, you must first understand recursion, and for this you first need to understand recursion, and for that you first need to understand recursion ... If you still understand recursion, then you understand recursion, which means you understand recursion, which means you understand recursion ... - Ilya Pirogov

5 answers 5

Without recursion and unnecessary nested loops.

It turns out for each array binary system. Accordingly, combinations of different genes may be 2 ^ (the length of the array). It is necessary to sort through all the different combinations ...

 var gens = [['AA', 'Bb', 'Cc'], ['aa', 'BB', 'Cc']]; for (u in gens) { var gen = gens[u]; for (var i = 0; i < 1 << gen.length; i++) {// 2^Π΄Π»ΠΈΠ½Π° массива ΠΊΠΎΠΌΠ±ΠΈΠ½Π°Ρ†ΠΈΠΉ var args = []; for (var j = 0; j < gen.length; j++) {// создаСм массив Ρ€Π°Π·Π½Ρ‹Ρ… сочСтаний var gi = (i & (1 << j)) >> j;// ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ индСкс Π±ΡƒΠΊΠ²Ρ‹ // ΠΏΠΎ Π½ΠΎΠΌΠ΅Ρ€Ρƒ ΠΊΠΎΠΌΠ±ΠΈΠ½Π°Ρ†ΠΈΠΈ // ΠΈ ΠΏΠΎ Π½ΠΎΠΌΠ΅Ρ€Ρƒ индСкса элСмСнта массива // (сорри Π² Π³Π΅Π½Π΅Ρ‚ΠΈΠΊΠ΅ Π½Π΅ силСн, // Ρ‡Ρ‚ΠΎ ΠΊΠ°ΠΊ называСтся Π½Π΅ Π² курсС) args.push(gen[j].charAt(gi));// заполняСм массив ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠ² для cross } var res = cross(args); if (!test(gomets[u], res, true)) { gomets[u].push(res); } } } 

JsFiddle test for making a list of arguments.

  • Thank you so much, but I thought that to realize this without eval is unrealistic (as long as there is little experience :) you could double-fold the answer, this would be double-plus! - Rules
  • Yes, it really works only two more questions to the guru please can make so that all the genes from gens [0] are crossed and recorded in gomets [0] and all the genes from gens [1] are crossed and recorded in gomets [1] atoms in you ALL genes and gens are crossed and recorded in gomets [0] And one more question what kind of operators & >> << when I heard somewhere that these are bitwise operators but I have no idea how to use them and can't find anything about them where you learned how to use them (operators & >> <<)? - Rules
  • one
    Corrected. << and >> - shift operators. Shift digits of the number in the binary system in the appropriate direction. & is the bitwise "and", if the bit is compared in both operands, it remains, if at least one of the bit's operands is zero, there will be zero (well, as usual "and" - && is only bitwise). for example: 10101 << 3 == 10101000; // is equivalent to multiplying by 2 ^ 3 10101 >> 3 == 10; // division without remainder by 2 ^ 3 10101 & 100 == 100; // The third bit is both How I don’t remember about them anymore :) - Yura Ivanov
  • Thanks a lot !!! - Rules
  • Where did you learn to program? - Rules
 for (var u in gens){ var tmp; var this_pair=gens[u]; for (var i=0; i<=this_pair.length; i++){ for(var j=0; j<=this_pair.length; j++){ tmp=cross([this_pair[0].charAt[i],this_pair[1].charAt[j]]); if(!test(gomets[u], tmp, true)){ gomets[u].push(tmp); } } } } 

not tested

  • 3
    Current at ... no need to take the length so often ... - Zowie
  • 2
    > Current at ... it is not necessary so often to consider the length ... And the fact that the gears will fray? :) PS By the way, length is not considered every time, it is just a property of the corresponding array. - Ilya Pirogov
  • I took the paired items, did not consider other options. It is necessary to rewrite and add another cycle. - Fucking Babay
  • @Ilya Pirogov is a strange benchmark. I gave 27,335 op / sec on the same Chrome machine, and FireFox is only 3.287 8 times slower; this is not normal. It seems to me that some kind of test is not so. - ReinRaus
  • @ReinRaus, such a difference is due to console.log() , I think. You can use any other, they are full of them: aku loop length , .length comparison , for loop length cache Or write your own. - Ilya Pirogov

Yes, you really need a recursion. It will be something like this:

 var genetic = function(gen, gomet, args) { // вытаскиваСм ΠΏΠ°Ρ€Ρƒ ΠΈΠ· стСка var pairs = gen.shift(); for (var pair in pairs) { // Π°Π½Π°Π»ΠΎΠ³ for (var X = 0; X <= 1; X++) for (var x in pairs[pair]) { // Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ для cross new_args = args.concat(pairs[pair][x]); // Ссли Π΅Ρ‰Π΅ ΠΎΡΡ‚Π°Π»ΠΈΡΡŒ ΠΏΠ°Ρ€Ρ‹ Π² стСкС if (gen.length) { // Ρ‚ΠΎ Π²Ρ‹Π·Ρ‹Π²Π°Π΅ΠΌ рСкурсивно genetic(gen.slice(), gomet, new_args); // ΠΈΠ½Π°Ρ‡Π΅ выполняСм основной Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌ } else { var res = cross(new_args); if (!test(gomet, res, true)) { gomet.push(res); } } } } } for (var pos in gens) { var gen = gens[pos]; var gomet = gomets[pos]; // slice(), ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ понадобится копия genetic(gen.slice(), gomet, []); } 
  • It turned out the same thing as @ Yoharny Babai :) - Ilya Pirogov
  • The problem is that all gens elements should be added to the cross function (see the UPD question!) - Rules
  • @Rules, really, did not read carefully. Updated the answer. - Ilya Pirogov

Recursion Roughly speaking, when a function calls itself:

 function foo(some_var){ alert(some_var); if(some_var<=0)return; else foo(--some_var); } foo(10); 
  • Okay, I put up with it, probably without eval'a I can make the code only after graduation :) - Rules
  • one
    @Rules, why are you giving up? The inflamed minds were disturbed here and now say no? - Anton Mukhin
  • Yes, I do not stop minds, let them think, and he will calm down for now, and I will manage with Eval. If minds throw a solution, I will use - Rules

Maybe that's it? (Needs verification)

 for (var u in gens) { var f = []; f.push(function(resarr) { var res = cross(resarr.reverse()); if(!test(gomets[u], res, true)) { gomets[u].push(res); } }); for(var i = gens[u].length; i-- > 0;) { var f1 = function() { var i1 = i; var l = f.length - 1; return function(resarr) { for(var a=0; a<2; a++) { resarr.push(gens[u][i1].charAt(a)); f[l](resarr); resarr.pop(); } } } var f2 = f1(); f.push(f2); } f[f.length-1]([]); } 

Although. If we take into account that all these for (var A, for (var B are cycles from 0 to 1, then we can make a common cycle (in this case, from 0 to 3) and divide them into bits with the operations / and%) And then the nested loops are not we need and all this trachoma