#javascript
Я делаю "генетический калькулятор", он должен "скрещивать" каждую букву каждого элемента gens[[],[]] с другой другого элемента. Есть такой код, который создаёт код, который затем исполняется: 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); } Суть в том, что он при gens=[['AA','Bb'],['aa','BB']]; создаёт сначала код: 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); } } } А потом 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); } } } Суть в том, чтобы код создавал столько вложенных циклов, сколько элементов в gens[u], например, gens[0]. Каждый цикл должен считать от 0 до 1 (так длина строки "AA" ,"bb" и тд 2 символа) и записывать результат в переменную, имя которой соответствует gens[u].[номер элемента/цикла].charAt(0); в теле самого вложенного цикла исполняется функция, ей в параметры должен попадать масив с элементами gens[u][0].charAt(имя счётчика цикла), тк индекс колеблется от 0 до 1, то цикл берёт каждую букву. Я думал над алгоритмом, ничего лучше придумать не смог, т.к количество элементов в gens[u] колеблется и все буквы всех элементов надо по очереди передавать функции, а для этого нужно столько циклов, сколько элементов в gens[u]. Собственно вопрос: можно ли это организовать без eval'a? ps Если что не понятно в вопросе, спрашивайте, я объясню. UPD: для gens=[['AA','Bb','Cc'],['aa','BB','Cc']]; генерируется код: 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); } } } }
Ответы
Ответ 1
Без рекурсии и излишних вложенных циклов. Тут получается для каждого массива двоичная система. Соответственно комбинаций разных генов может быть 2^(длина массива). Надо перебрать все различные комбинации... 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 тест для составления списка аргументов.Ответ 2
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); } } } } не тестировалосьОтвет 3
Да, действительно нужна рекурсия. Будет, что-то в этом родe: 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, []); }Ответ 4
Рекурсия. Грубо говоря когда функция вызывает сама себя: function foo(some_var){ alert(some_var); if(some_var<=0)return; else foo(--some_var); } foo(10);Ответ 5
Может вот так? (Нуждается в проверке) 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]([]); } Хотя. Если учесть, что все эти for(var A, for(var B -- циклы от 0 до 1, то можно сделать общий цикл (в этом случае от 0 до 3) и разбить на биты операциями / и % И тогда вложенные циклы не нужны и вся эта трахомудрия тоже
Комментариев нет:
Отправить комментарий