Страницы

Поиск по вопросам

четверг, 19 декабря 2019 г.

Как сделать такой же код без eval'a?

#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) и разбить на биты операциями / и % И тогда вложенные циклы не нужны и вся эта трахомудрия тоже

Комментариев нет:

Отправить комментарий