Duplicar elementos de uma matriz, exceto o primeiro e o último elementos

0

Eu tenho uma matriz e gostaria de repetir cada elemento, exceto o primeiro e o último elementos.

Por exemplo, se a matriz tiver cinco elementos 1 2 3 4 5 , depois da repetição, seus elementos deverão ser 1 2 2 3 3 4 4 5 .

Meus comandos bash são

$ newarr=("${myarr[0]}")
$ for i in $(seq 1 $((${#myarr[@]}-2))) ; do newarr+=( "${myarr[i]}" "${myarr[i]}"); done
$ newarr+=("${myarr[-1]}")

Existe um caminho mais claro do que o meu?

Também estou querendo saber como envolvê-lo em uma função que usa myarr como argumento e retorna newarr . (Depois de criar essa função, vou ler uma matriz de um arquivo, para que cada elemento armazene uma linha no arquivo e, em seguida, chame a função na matriz. Se criar essa função não for uma boa abordagem, avise-me .)

Obrigado.

    
por Tim 17.11.2018 / 19:12

3 respostas

2

Você pode diminuir o número de operações e pular a chamada para seq :

for (( i = 1; i < ${#myarr[@]} - 1; ++i )); do
    newarr+=( "${myarr[i]}" "${myarr[i]}" )
done
newarr=( "${myarr[0]}" "${newarr[@]}" "${myarr[-1]}" )

Isso pressupõe que newarr esteja vazio para começar. Do unset newarry primeiro, se não for.

Como uma função (isso modifica a matriz que é passada):

dup_interal_items () {
    typeset -n arr=$1
    local tmparr

    for (( i = 1; i < ${#arr[@]} - 1; ++i )); do
        tmparr+=( "${arr[i]}" "${arr[i]}" )
    done
    arr=( "${arr[0]}" "${tmparr[@]}" "${arr[-1]}" )
}

O nome da matriz é passado para a função e a variável de referência de nome arr é usada para acessar os elementos na matriz. No final, o array original é atualizado para conter o resultado.

Eu fiz dessa maneira, em vez de retornar uma matriz, pois você só pode retornar um status de saída de uma função. A outra abordagem seria passar os nomes de uma matriz de entrada e uma matriz de saída e usar duas variáveis de referência de nome na função.

Ou, você poderia, possivelmente, echo ou printf os valores na função (nesse caso, não é necessário construir um novo array) e, em seguida, analisar esses dados no código principal. A função seria, então, necessária para ser chamada dentro de uma substituição de comando.

Observe que você não pode chamar essa função com uma matriz chamada arr devido às regras específicas de definição de escopo de nome usadas por bash . Você pode querer renomear a variável arr na função se isso for um problema.

Teste:

$ myarr=( 1 2 3 "here we go" )
$ dup_interal_items myarr
$ printf 'Element: %s\n' "${myarr[@]}"
Element: 1
Element: 2
Element: 2
Element: 3
Element: 3
Element: here we go

Para duplicar todas as linhas de um arquivo, exceto a primeira e a última linha:

sed -e '1b' -e '$b' -e 'p' <file

O script sed ramifica para o final (onde há uma instrução de impressão implícita) se estiver na primeira ou na última linha, mas imprime todas as outras linhas (todas as outras linhas são, portanto, explicitamente impressas pela última p e implicitamente impressos).

Ou, conforme contribuído por don_crissti,

sed 'p;1d;$d' <file

que imprime explicitamente cada linha, termina o ciclo da primeira e última linha, mas imprime implicitamente todas as outras linhas (uma segunda vez).

Um programa equivalente em awk que não armazena mais do que uma única linha na memória seria não trivial para escrever.

    
por 17.11.2018 / 19:27
1

Experimente também - não é necessária nenhuma função -

$ ARR=(1 2 3 4 5)
$ IFS=$'\n\t '
$ readarray NEWARR < <(echo "${ARR[*]}" | sed '1!p; $d')
$ echo ${NEWARR[@]}
1 2 2 3 3 4 4 5

ou até mesmo

NEWARR=($(printf "%s\n" ${ARR[@]} | sed '1!p; $d'))
    
por 17.11.2018 / 23:12
1

Uma solução que aceita novas linhas:

#!/bin/bash
arr=( 1 2 "3 3" $'41\n42' 5 )

readarray -t -d $'
$ ./script
<1>
<2>
<2>
<3 3>
<3 3>
<41
42>
<41
42>
<5>
' newarray < <(printf '%s
#!/bin/bash
arr=( 1 2 "3 3" $'41\n42' 5 )

readarray -t -d $'
$ ./script
<1>
<2>
<2>
<3 3>
<3 3>
<41
42>
<41
42>
<5>
' newarray < <(printf '%s%pre%' "${arr[@]}" | sed -z '1!p; $d') printf '<%s>\n' "${newarr[@]}"
' "${arr[@]}" | sed -z '1!p; $d') printf '<%s>\n' "${newarr[@]}"

é executado como:

%pre%     
por 18.11.2018 / 04:21