duvida com sed / for [RESOLVIDO]

1. duvida com sed / for [RESOLVIDO]

matheus franco
mlfranco

(usa Outra)

Enviado em 14/02/2020 - 14:58h

Boa tarde!

Estou com o seguinte problema:

Tenho uma lista ( 1 nome/string por linha), e quero transformar essa lista de string em uma lista de numeros, onde as strings iguais tenham o mesmo número.

exemplo:
entrada | saida
Pato 1
Pato 1
Cachorro 2
Gato -> 3
Leão 4
Cachorro 2
Pato 1

Tentei fazer algo como

for x in $(cat arquivo | sort | uniq);do cat arquivo | sed -e 's/$x/2/';done

mas não estou sabendo utilizar a variavel "x" do loop, e tambem como colocar o index/contador (que estou no loop) para incrementar o numero pelo qual subistituo a palavra...

Desde ja agradeço a ajuda =D



  


2. Re: duvida com sed / for [RESOLVIDO]

Marcelo Oliver
msoliver

(usa Debian)

Enviado em 14/02/2020 - 19:14h


mlfranco escreveu:

Boa tarde!

Estou com o seguinte problema:

Tenho uma lista ( 1 nome/string por linha), e quero transformar essa lista de string em uma lista de numeros, onde as strings iguais tenham o mesmo número.

exemplo:
entrada | saida
Pato 1
Pato 1
Cachorro 2
Gato -> 3
Leão 4
Cachorro 2
Pato 1

Tentei fazer algo como
for x in $(cat arquivo | sort | uniq);do cat arquivo | sed -e 's/$x/2/';done
mas não estou sabendo utilizar a variavel "x" do loop, e tambem como colocar o index/contador (que estou no loop) para incrementar o numero pelo qual subistituo a palavra...

Desde ja agradeço a ajuda =D


Boa noite mlfranco,
segue sugestão:
n=0;
for bicho in $(sort -u lista.txt);do
let n++;
sed -n "/^${bicho}$/s/$/ ${n}/p" lista.txt ; #Na linha que tem o "bicho", coloque o "n" no final.
done

Saída:
Cachorro 1
Cachorro 1
Gato 2
Leão 3
Pato 4
Pato 4
Pato 4

______________________________________________________________________
Importante: echo -e "\n$(lynx --dump goo.gl/a9KeFc|sed -nr '/^[ ]+Se/,/dou.$/p')\n"
Att.: Marcelo Oliver
______________________________________________________________________


3. Re: duvida com sed / for [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 17/02/2020 - 17:09h

A solução do msoliver funciona. Contudo, acho importante notar que ela tem complexidade quadrática (no pior caso, um arquivo com N linhas vai ser inteiramente processado N vezes) e produz uma saída que altera a ordem dos elementos, o que pode até ser aceitável, mas não corresponde ao exemplo de saída mostrado pelo OP.

Uma forma mais otimizada de fazer é fazer numa passada só, e usar o recurso de array associativo do bash ou ksh para verificar se uma palavra nova existe e então recuperar o valor inteiro associado, ou associar-lhe um valor inteiro novo, caso ainda não exista. A principal vantagem de fazer desse modo é que a complexidade do algoritmo passa de quadrática para essencialmente linear (assumindo que o array associativo tem complexidade constante, o que costuma ser aproximadamente verdadeiro quando são implementados com tabelas hash). Por outro lado, como o shell usa seus arrays associativos exclusivamente em memória, um arquivo de entrada excessivamente grande poderia provocar esgotamento de recursos.

Não vou colocar aqui nenhum exemplo porque não sei se a pergunta se refere a trabalho escolar. Contudo, para aprender a usar arrays associativos, a documentação do Bash é mais do que suficiente, e existem exemplos de uso aqui mesmo, nesta comunidade do fórum.


... “Principium sapientiae timor Domini, et scientia sanctorum prudentia.” (Proverbia 9:10)


4. Re: duvida com sed / for [RESOLVIDO]

matheus franco
mlfranco

(usa Outra)

Enviado em 17/02/2020 - 20:31h

Boa noite!
realmente a complexidade fica bem elevada, eu pesquisei um pouco e consegui da seguinte maneira :

i=0;for x in $(cat entrada.txt | sort | uniq);do i=$(( $i + 1 )); cat entrada.txt | sed -i s/$x/$i/ entrada.txt;done

mas não fica nada performatico alem do problema de recursos... vou tentar uma outra implementação como voce sugeriu....
Obrigado

PS.: não é trabalho de faculdade não

paulo1205 escreveu:

A solução do msoliver funciona. Contudo, acho importante notar que ela tem complexidade quadrática (no pior caso, um arquivo com N linhas vai ser inteiramente processado N vezes) e produz uma saída que altera a ordem dos elementos, o que pode até ser aceitável, mas não corresponde ao exemplo de saída mostrado pelo OP.

Uma forma mais otimizada de fazer é fazer numa passada só, e usar o recurso de array associativo do bash ou ksh para verificar se uma palavra nova existe e então recuperar o valor inteiro associado, ou associar-lhe um valor inteiro novo, caso ainda não exista. A principal vantagem de fazer desse modo é que a complexidade do algoritmo passa de quadrática para essencialmente linear (assumindo que o array associativo tem complexidade constante, o que costuma ser aproximadamente verdadeiro quando são implementados com tabelas hash). Por outro lado, como o shell usa seus arrays associativos exclusivamente em memória, um arquivo de entrada excessivamente grande poderia provocar esgotamento de recursos.

Não vou colocar aqui nenhum exemplo porque não sei se a pergunta se refere a trabalho escolar. Contudo, para aprender a usar arrays associativos, a documentação do Bash é mais do que suficiente, e existem exemplos de uso aqui mesmo, nesta comunidade do fórum.


... “Principium sapientiae timor Domini, et scientia sanctorum prudentia.” (Proverbia 9:10)





5. Re: duvida com sed / for [RESOLVIDO]

matheus franco
mlfranco

(usa Outra)

Enviado em 17/02/2020 - 20:31h

Obrigado pela sugestão!

msoliver escreveu:


mlfranco escreveu:

Boa tarde!

Estou com o seguinte problema:

Tenho uma lista ( 1 nome/string por linha), e quero transformar essa lista de string em uma lista de numeros, onde as strings iguais tenham o mesmo número.

exemplo:
entrada | saida
Pato 1
Pato 1
Cachorro 2
Gato -> 3
Leão 4
Cachorro 2
Pato 1

Tentei fazer algo como
for x in $(cat arquivo | sort | uniq);do cat arquivo | sed -e 's/$x/2/';done
mas não estou sabendo utilizar a variavel "x" do loop, e tambem como colocar o index/contador (que estou no loop) para incrementar o numero pelo qual subistituo a palavra...

Desde ja agradeço a ajuda =D


Boa noite mlfranco,
segue sugestão:
n=0;
for bicho in $(sort -u lista.txt);do
let n++;
sed -n "/^${bicho}$/s/$/ ${n}/p" lista.txt ; #Na linha que tem o "bicho", coloque o "n" no final.
done

Saída:
Cachorro 1
Cachorro 1
Gato 2
Leão 3
Pato 4
Pato 4
Pato 4

______________________________________________________________________
Importante: echo -e "\n$(lynx --dump goo.gl/a9KeFc|sed -nr '/^[ ]+Se/,/dou.$/p')\n"
Att.: Marcelo Oliver
______________________________________________________________________





6. Re: duvida com sed / for [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 18/02/2020 - 21:06h

Seguem algumas maneiras de fazer, usando Bash, KSH, Perl, Python e AWK.
#!/bin/bash

declare -A dicionario
seq=0
while read palavra; do
[[ -z "${dicionario[$palavra]}" ]] && dicionario[$palavra]=$((++seq))
echo -e "$palavra\t${dicionario[$palavra]}"
done

#!/bin/ksh

typeset -A dicionario
seq=0
while read palavra; do
[[ -z "${dicionario[$palavra]}" ]] && dicionario[$palavra]=$((++seq))
print "$palavra\t${dicionario[$palavra]}"
done

#!/usr/bin/perl

$seq=0;
while(defined($palavra=<>)){
chomp($palavra);
$dicionario{$palavra}=++$seq unless exists($dicionario{$palavra});
print "$palavra\t$dicionario{$palavra}\n";
}

#!/usr/bin/python3

import sys

dicionario={ }
seq=0
for linha in sys.stdin:
palavra=linha.rstrip("\n")
if palavra not in dicionario:
seq=seq+1
dicionario[palavra]=seq
print(palavra, "\t", dicionario[palavra])

#!/usr/bin/awk -E

BEGIN { seq=0 }
{
if(!($0 in dicionario)){ dicionario[$0]=++seq }
print $0 "\t" dicionario[$0]
}


E alguns resultados, aplicadas sobre um arquivo de entrada que foi gerado copiando cinco vezes o conteúdo do arquivo /usr/share/dict/words (que na minha máquina tem 102305 linhas, totalizando 511525 linhas), com o MD5 de cada saída, para mostrar que todas são idênticas.
bash:
real 0m38.581s
user 0m30.254s
sys 0m8.249s
6dc867d2e691c8b8b16469e677effc57 saida-bash.txt

ksh:
real 0m10.967s
user 0m6.354s
sys 0m4.603s
6dc867d2e691c8b8b16469e677effc57 saida-ksh.txt

pl:
real 0m0.487s
user 0m0.458s
sys 0m0.028s
6dc867d2e691c8b8b16469e677effc57 saida-pl.txt

py:
real 0m1.105s
user 0m1.079s
sys 0m0.024s
6dc867d2e691c8b8b16469e677effc57 saida-py.txt

awk:
real 0m0.464s
user 0m0.415s
sys 0m0.048s
6dc867d2e691c8b8b16469e677effc57 saida-awk.txt



... “Principium sapientiae timor Domini, et scientia sanctorum prudentia.” (Proverbia 9:10)






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts