Script Bash para ler a lista de mais de 20 itens na matriz e, em seguida, gerar todas as combinações de quatro itens da lista

1

Eu tenho um arquivo "ingredients.txt" que tem uma lista de 38 palavras (uma para cada linha). Eu descobri como lê-lo em uma matriz

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

getArray "ingredients.txt"

Mas agora como obter a saída de todas as combinações de exatamente 4 palavras da lista de 38?

EDIT: Para responder a um comentário, quero dizer combinações e não permutações e repetições não são válidas. Quatro palavras únicas em cada combinação.

Para esclarecer ainda mais, pense nisso como desenhar quatro bolinhas de 38 cores diferentes de uma sacola. Não há duas cores iguais. Depois de desenhar um vermelho, é impossível desenhar outro vermelho para essa combinação. Você desenha quatro, anota as cores e as coloca de volta na sacola e desenha outras quatro. Se você obtiver {azul, amarelo, roxo, vermelho} e {amarelo, roxo, vermelho, azul} eles não serão contados separadamente. Eu só quero combinações, não permutações.

Além disso, quero que cada combinação seja impressa (voltando à lista de ingredientes): cebola, queijo, carne, pão alface, cenoura, aipo, rabanete cenoura, alface, aipo, vinagre etc.

Espero que isso esteja claro.

    
por gracious1 12.10.2018 / 07:43

4 respostas

2

Em Python:

import itertools.combinations

with open('ingredients.txt') as fd:
    words= fd.readlines()
    for combination in itertools.combinations(words, 4):
        print(combination)
    
por 12.10.2018 / 10:08
0

Eu tentei usar o 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']
    
por 12.10.2018 / 14:11
0

Apenas para se divertir, uma versão em bash simples (que eu não recomendo usar para listas longas, é bastante lento (como deveria ser esperado), leva mais de dois minutos para fazer no shell que em c é feito em meio segundo.):

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

Executando como:

$ ./script 4 38

imprimirá:

$ ./script 4 38 | wc -l
73815

Como a matemática confirmará (o fato é uma função definida da biblioteca):

$ bc <<<"r=4;n=38;fact(n)/(fact(r)*fact(n-r))"    # n! / ( r! × (n-r)! )
73815
    
por 14.10.2018 / 01:22
-1

Bem, tente com o código abaixo

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"
    
por 12.10.2018 / 07:55