2014-04-29 3 views
6

Я хочу, чтобы произвести такой файл (декартово произведение [1-3]X[1-5]):Как производить декартовую продукцию в bash?

1 1 
1 2 
1 3 
1 4 
1 5 
2 1 
2 2 
2 3 
2 4 
2 5 
3 1 
3 2 
3 3 
3 4 
3 5 

Я могу сделать это с помощью вложенных циклов, как:

for i in $(seq 3) 
do 
    for j in $(seq 5) 
    do 
     echo $i $j 
    done 
done 

есть какое-либо решение без использования циклов?

ответ

8

Объединение двух brace expansions!

$ printf "%s\n" {1..3}" "{1..5} 
1 1 
1 2 
1 3 
1 4 
1 5 
2 1 
2 2 
2 3 
2 4 
2 5 
3 1 
3 2 
3 3 
3 4 
3 5 

Это работает с использованием одного расширения распорки:

$ echo {1..5} 
1 2 3 4 5 

, а затем в сочетании с другой:

$ echo {1..5}+{a,b,c} 
1+a 1+b 1+c 2+a 2+b 2+c 3+a 3+b 3+c 4+a 4+b 4+c 5+a 5+b 5+c 
+0

делает {1..3} расширять оболочкой? –

+0

Да, '{1..3}' такой же, как 'seq 3' или' seq 1 3', просто он поставляется с оболочкой. – fedorqui

+0

есть ли какой-либо другой с помощью пасты? –

6

Лучшей альтернатива для декартова продукта в Баше, безусловно, - как указана @fedorqui - использовать расширение параметра. Однако, если ваш вход не легко может быть произведен (т. Е. Если {1..3} и {1..5} не хватает), вы можете просто использовать join.

Например, если вы хотите преобразовать декартовое произведение двух файлов , скажем, «a.txt» и «b.txt», вы можете сделать следующее. Во-первых, эти два файла:

$ echo -en {a..c}"\tx\n" | sed 's/^/1\t/' > a.txt 
$ cat a.txt 
1 a x 
1 b x 
1 c x 

$ echo -en "foo\nbar\n" | sed 's/^/1\t/' > b.txt 
$ cat b.txt 
1 foo 
1 bar 

Уведомление команда sed используется предварять каждую строку с идентификатором. Идентификатор должен быть одинаковым для всех строк, и для всех файлов, поэтому join предоставит вам декартовую продукцию - вместо того, чтобы отложить часть результирующих строк. Таким образом, join идет следующим образом:

$ join -j 1 -t $'\t' a.txt b.txt | cut -d $'\t' -f 2- 
a x foo 
a x bar 
b x foo 
b x bar 
c x foo 
c x bar 

После того как файлы соединяются, cut используется в качестве альтернативы, чтобы удалить столбец «1», ранее предваряется.

+0

что вы напишите как соединение, действительно присоединяется (http://en.wikipedia.org/wiki/Join_%28relational_algebra%29#Joins_and_join-like_operators), мне не нужно присоединяться. то, что я хочу, является декартовым продуктом (http://en.wikipedia.org/wiki/Cartesian_product). –

+1

@ طاهر Ну, когда вы соединяете каждую строку из одной таблицы с строками из другой таблицы, т. Е. Когда вы выполняете [* cross join *] (http://en.wikipedia.org/wiki/Join_%28SQL % 29 # Cross_join), ваш результат является декартовым продуктом. – Rubens

+1

Преимущество этого решения заключается в том, что bash не позволяет использовать переменные в расширениях фигурных скобок. Вы можете использовать переменные в расширении скобок с помощью eval, но тогда вы используете eval. – Erik

1

версия короче (но Hacky) ответа Рубенса:

join -j 999999 -o 1.1,2.1 file1 file2 

Поскольку поле 999999, скорее всего, не существуют считается равным для обоих множеств, и поэтому join должны сделать декартово произведение. Он использует память O (N + M) и производит выход на скорости 100..200 Мбит/с на моей машине.

Мне не нравится метод расширения оболочки скорлупы, например echo {1..100}x{1..100}, для больших наборов данных, поскольку он использует память O (N * M) и может использоваться при небрежном переносе машины на колени. Это трудно остановить, потому что ctrl + c не прерывает расширение скобки, которое делает сама оболочка.

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

  • Нет связанных вопросов^_^