Bash 脚本将 20 多个项目的列表读入数组,然后从列表中生成四个项目的所有组合

Bash 脚本将 20 多个项目的列表读入数组,然后从列表中生成四个项目的所有组合

我有一个文件“ingredients.txt”,其中包含 38 个单词的列表(每行一个)。我已经弄清楚如何将其读入数组

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

getArray "ingredients.txt"

但是现在如何从 38 个列表中输出恰好 4 个单词的所有组合?

编辑:为了回应评论,我的意思是组合而不是排列,并且重复无效。每个组合中有四个独特的单词。

为了进一步澄清,可以将其视为从袋子中抽取 4 个 38 种不同颜色的弹珠。没有两种颜色是一样的。一旦你抽出了一个红色的组合,就不可能再为该组合抽出另一个红色的组合。你画了四个,记下颜色,然后把它们放回袋子里,然后再画四个。如果您得到{蓝色,黄色,紫色,红色}和{黄色,紫色,红色,蓝色},则它们不会单独计算。我只想要组合,而不是排列。

另外,我想要打印每个组合(回到配料表):洋葱,奶酪,肉,生菜,胡萝卜,芹菜,萝卜胡萝卜,生菜,芹菜,醋等。

我希望这一点很清楚。

答案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 编写的版本(我不建议在长列表中使用它,它非常慢(正如预期的那样),在 shell 中需要两分钟多才能完成 c 中完成的操作半秒。):

#!/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"

相关内容