Encontre o conjunto de complementos de uma matriz?

2

Seguindo esta pergunta , onde eu Desejo extrair 10 linhas aleatórias de um arquivo, agora eu quero também ter as 90 linhas restantes como um arquivo separado.

Como o documento tem 100 linhas, indexando de 1 a 100, o problema se resume a encontrando o conjunto de complementos de ind em 1, 2, ..., 100 , onde

ind=$(shuf -i 1-100 -n 10 | sort -n)

Então minhas perguntas são

  1. Como posso gerar a matriz 1, 2, ..., 100 de maneira eficiente? e
  2. Parece que isso pode ser feito com comm . Se sim, como devo fazer comm em matrizes (não arquivos)?
por Sibbs Gambling 27.05.2015 / 18:45

4 respostas

4

Com base na minha proposta do outro segmento:

awk '
  BEGIN { srand(); do a[int(100*rand()+1)]; while (length(a)<10) }
  NR in a
' ~/orig.txt > ~/short.txt

isso pode ser alterado para criar os dois arquivos:

awk -v range=100 -v offset=1 -v amount=10 '
  BEGIN { srand(); do a[int(range*rand()+offset)]; while (length(a)<amount) }
  NR in a    { print > "short.txt" }
  !(NR in a) { print > "rest.txt" }
' ~/orig.txt

(Observe que dentro de awk você não pode usar ~ . É possível, porém, usar HOME a ENVIRON[] , como em: print > ENVIRON["HOME"] "/short.txt" , ou resp., print > ENVIRON["HOME"] "/rest.txt" .)

    
por 27.05.2015 / 19:30
2

Ok, pensando duas vezes - eu trabalhei muito maneira nisso. Você só precisa disso:

shuf -i 1-100 -n10 |
sed 's/$/{p;b\n}/' |
sed -nf - -e 'w separate_file' infile >outfile

Embora você possa precisar de uma nova linha literal no lugar do n na substituição sed . De qualquer forma, isso faz o mesmo que abaixo - ele simplesmente não se incomoda em fazer todas as outras 90 linhas - eles apenas se encaixam porque estão no arquivo - então eles não precisam de nenhuma consideração especial.

Este é o negócio todo:

set  " $(shuf -i 1-100 -n 10) "
while [ "$((i+=1))" -le 100 ]
do    [ -z "${1##*[!0-9]$i[!0-9]*}" ]
      printf "$i%.$((!$?))s%.$?s\n" p H 
done| sed -nf - -e '$!d;x;s/.//p' <infile >outfile

Existe basicamente basicamente um script sed semelhante a:

1H
2H
3H
4p
5H
...
90p
91H
...

E assim por diante até 100. Na última linha - depois que todas as linhas selecionadas aleatoriamente já tiverem sido p rinted, nós e x mudaremos para H old space, s/// ubstituiremos o primeiro inseriu \n ewline character, e p rint o lote do resto.

Para fazer isso sem o loop de shell, você pode fazer:

set  "$(shuf -i 1-100 -n 10)"
{ seq 100 | grep -Fxv "$1"; echo "$1"; } |
sed '1,90s/$/H/;91,$s/$/p/' |
sed -nf - -e '$!d;x;s/.//p' <infile >outfile

Mas não tenho certeza se nessa escala isso seria benéfico.

De qualquer forma, usei um arquivo de saída seq 100 como teste e, depois de executá-lo, imprimi ...

3
4
5
19
57
63
64
73
80
88
1
2
6
7
8
9
10
11
12
13
14
15
16
...

... e até 100 para todas as linhas não incluídas no aleatório inicial 100.

    
por 28.05.2015 / 02:13
1

Aqui está outra solução com bash. Primeiro, você pode querer criar uma matriz a partir da sua variável ind:

ind=($(shuf -i 1-100 -n 10 | sort -n))

Para criar uma matriz com números de 1..100, uma maneira fácil é esta:

numbers=({1..100})

Para chegar ao complemento, eu utilizaria uniq -u. Esse comando pode classificar todas as duplicatas de uma lista já classificada. O comando final da colagem apenas coloca todos os valores em uma única linha novamente.

complement=($(echo ${ind[*]} ${numbers[*]} | sed 's/ /\n/g' | sort -n | uniq -u | paste -sd " " - ))
echo ${complement[*]}

Apenas repensando a pergunta, tudo isso também pode ser feito sem as matrizes bash:

ind=$(shuf -i 1-100 -n 10 | sort -n)
echo $ind {1..100} | sed 's/ /\n/g' | sort -n | uniq -u | paste -sd " " -
    
por 05.04.2018 / 14:10
0

Eu acredito que você pode fazer tudo na linha de comando, mas alguns problemas são melhor resolvidos com uma linguagem de programação real. Por exemplo, uma solução baseada em python para o seu problema seria:

import random
import pprint

with open("file.txt", "w") as f:
  # create a file filled with numbers from 00 to 99
  f.writelines(map(lambda x: "%02d\n" % x, range(100)))

with open("file.txt") as f:
  # read it and assign each line to array, strip newlines 
  ar = set(map(lambda x: x.strip(), f.readlines()))

selection = set(random.sample(ar, 10))
rest = ar - selection

pprint.pprint(selection)
pprint.pprint(rest)
    
por 27.05.2015 / 19:13