20以上のアイテムのリストを配列として読み込み、リストから4つのアイテムのすべての組み合わせを生成するBashスクリプト

20以上のアイテムのリストを配列として読み込み、リストから4つのアイテムのすべての組み合わせを生成するBashスクリプト

38ワード(1行に1つ)のリストを含む "ingredients.txt"ファイルがあります。配列で読む方法を見つけました。

getArray() {
    array=() 
    while IFS= read -r line 
    do
        array+=("$line")
    done < "$1"
}

getArray "ingredients.txt"

しかし、今38のリストから正確に4つの単語のすべての組み合わせを出力する方法は何ですか?

編集:コメントに応じて順列ではなく組み合わせを意味し、重複は効果がありません。各組み合わせには4つの固有の単語があります。

もっと明確に説明するには、これをバッグから38色のビーズ4個を選ぶと考えてみてください。 2つの色が同じではありません。赤の組み合わせを一度描画すると、その組み合わせに対して他の赤の組み合わせを描画することはできません。 4つを塗り、色を記録し、再びバッグに入れて4つを塗ります。 {ブルー、イエロー、パープル、レッド}と{イエロー、パープル、レッド、ブルー}を取得すると、別々にカウントされません。私は順列ではなく組み合わせをしたいです。

また、玉ねぎ、チーズ、肉、レタス、ニンジン、セロリ、てんとう根、レタス、セロリ、酢などの各組み合わせ(成分リストに戻る)を印刷したいと思います。

これがはっきりしていることを願っています。

答え1

Pythonでは:

import itertools.combinations

with open('ingredients.txt') as fd:
    words= fd.readlines()
    for combination in itertools.combinations(words, 4):
        print(combination)

答え2

Pythonを試してみます。

>>> a
['praveen', 'ajay', 'abhi', 'chetan', 'abh', 'cat']


for i in range(0,len(a),4):
...     print a[i:i+4]
...
['praveen', 'ajay', 'abhi', 'chetan']
['abh', 'cat']

答え3

楽しみのために通常のbashで書かれたバージョンです(長いリストと一緒に使用することはお勧めできません。非常に遅いです(予想どおり)。 :

#!/bin/bash -
set -u

readarray -t b <ingredients.txt

r=${1:-3}
n=${2:-5}

main(){
          combinations
      }


combinations(){  : ${r:=3}    ${n:=5}    # default values

        ## The first line of elements is easy, fill an array of r elements:
        for ((i=0 ; i<r ; i++)); do 
            a[i]=$i
        done
        printelements

        ## Up to the maximum permitted value of the first array element.
        while (( a[0] < n-r )); do
            ## search backwards on the array for a value less than maximum.
            for ((i = r-1; i >= 0; i--)); do
            ## If an item is below its maximum permitted value...
            if ((a[i] < n-r+i )); then 
                ## increment it:
                ((a[i]++))
                break
            fi
            done
            ## Fill the rest of the array with consecutive values:
            for (( i = i + 1 ; i < r ; i++ )); do
            (( a[i] = a[i-1] + 1 ))
            done
            ## Print the current combination of items:
            printelements
        done
         }

printelements(){ : #p=${a[@]/%/ }; printf '%s\n' "<${p% }>"; }
                 s=""
                 for i in "${a[@]}"; do
                     printf '%s' "$s" "${b[i]}"
                     s=" "
                 done
                 echo
               }

main

次のように実行します。

$ ./script 4 38

以下を印刷します。

$ ./script 4 38 | wc -l
73815

数学的に確認されているように(実際はライブラリ定義関数です):

$ bc <<<"r=4;n=38;fact(n)/(fact(r)*fact(n-r))"    # n! / ( r! × (n-r)! )
73815

答え4

それでは、以下のコードを試してください。

getArray() {
    array=() 
    while IFS= read -r line 
    do
        array+=("$line")
    done < "$1"
    for i in ${!array[@]}
    do
           if [ ${#array[$i]} == 4 ]; then
                    echo "${array[$i]}"
           fi
    done
}

getArray "ingredients.txt"

関連情報