2015-11-26 3 views
1

Я пытаюсь выполнить итерацию через n-мерное пространство с серией вложенных for-loops в bash.Выполнение произвольного числа вложенных циклов в bash

VAR1="a b c d e f g h i" 
VAR2="1 2 3 4 5 6 7 8 9" 
VAR3="a1 b2 b3 b4 b5 b6" 

for i1 in $VAR1; do 
    for i2 in $VAR2; do 
     for i3 in $VAR3; do 
      echo "$i1 $i2 $i3" 
     done 
    done 
done 

Теперь, когда я получаю больше размеров перебирать, я понимаю, что это было бы легче/лучше, чтобы иметь возможность задать произвольное число переменных перебрать.

Если бы я использовал более сложный язык программирования, я мог бы использовать рекурсию для передачи списка списков функции, выпадающего списка, перебора по нему, рекурсивного вызова функции каждый раз через цикл, передачи теперь сокращенный список списков и сборка n-кортежей, когда я иду.

(я пытался псевдокод, что это будет выглядеть, но больно мне голова думать о рекурсии и построение списков.)

function iterate_through(var list_of_lists) 
    this_list=pop list_of_lists 
    var new_list = [] 
    for i in this_list 
     new_list.push(i) 
     new_list.push(iterate_through(list_of_lists)) 
    # return stuff 
    # i gave up about here, but recursion may not even be necessary 

Кто-нибудь есть предложение о том, как выполнить итерацию через произвольное число vars в bash? Имея в виду, цель состоит в том, чтобы итерации через все n-мерное пространство, и что итерация не обязательно является частью решения.

ответ

1

Если parallel является приемлемым, то можно было бы упростить вложенную for петлю как

parallel -P1 echo {1} {2} {3} ::: $VAR1 ::: $VAR2 ::: $VAR3 

В общем случае, это может быть, возможно, целесообразно сначала собрать эту команду, а затем выполнить его ...

1

Вы можете использовать рекурсию для вычисления декартово произведение

следующий скрипт будет делать работу с переменной входной длины вектора:

#!/bin/bash 

dim=("a b c d e f g h i" "1 2 3 4 5 6 7 8 9" "a1 b2 b3 b4 b5 b6") 

function iterate { 

    local index="$2" 

    if [ "${index}" == "${#dim[@]}" ]; then 

     for ((i=0; i<=${index}; i++)) 
     do 
      echo -n "${items[$i]} " 
     done 
     echo "" 
    else 
     for element in ${dim[${index}]}; do 
      items["${index}"]="${element}" 
      local it=$((index+1)) 
      iterate items[@] "$it" 
     done 
    fi 
} 

declare -a items=("") 

iterate "" 0 

Следующая суть будет принимать в качестве входных аргументов всех ваших размеров массива (с разделёнными пробелами элементами): https://gist.github.com/bertrandmartel/a16f68cf508ae2c07b59

Смежные вопросы