Соберите данные с похожими столбцами - PullRequest
2 голосов
/ 16 марта 2012

Я хочу отфильтровать данные из текстового файла в Unix. У меня есть текстовый файл в Unix, как показано ниже:

A 200
B 300
C 400
A 100
B 600
B 700

Как я могу изменить / создать данные, как показано ниже, из приведенных выше данных в awk?

A 200 100
B 300 600 700
C 400 

Я не так хорош в awk, и я считаю, что awk / perl лучше для этого.

Ответы [ 6 ]

3 голосов
/ 16 марта 2012
awk 'END {
  for (R in r) 
    print R, r[R]
  }
{
  r[$1] = $1 in r ? r[$1] OFS $2 : $2
  }' infile

Если важен порядок значений в первом поле, потребуется больше кода.Решение будет зависеть от вашей awk реализации и версии.

Объяснение:

r[$1] = $1 in r ? r[$1] OFS $2 : $2

Установите значение элемента массива r $ 1 в:

  • если ключ $ 1 уже присутствует: $ 1 в r, добавьте OFS $ 2 к существующему значению
  • , в противном случае установите для него значение $ 2

выражение?если true: если false, это троичный оператор.Подробнее см. троичная операция .

2 голосов
/ 16 марта 2012

Вы можете сделать это так, но с Perl всегда есть несколько способов сделать это:

my %hash; 
while(<>) { 
    my($letter, $int) = split(" "); 
    push @{ $hash{$letter} }, $int;
} 

for my $key (sort keys %hash) {
    print "$key " . join(" ", @{ $hash{$key} }) . "\n";
}

Должно работать так:

$ cat data.txt | perl script.pl
A 200 100
B 300 600 700
C 400
1 голос
/ 16 марта 2012

Не зависит от языка.Больше похоже на псевдокод, но вот идея:

- Get all lines in an array
- Set a target dictionary of arrays

- Go through the array :
       - Split the string using ' '(space) as the delimiter, into array parts
       - If there is already a dictionary entry for `parts[0]` (e.g. 'A'). 
         If not create it.
       - Add `parts[1]` (e.g. 100) to `dictionary(parts[0])`

И все!: -)

Я бы сделал это, вероятно, на Python, но это скорее дело вкуса.

0 голосов
/ 16 марта 2012

Это может работать для вас:

sort -sk1,1 file | sed ':a;$!N;s/^\([^ ]*\)\( .*\)\n\1/\1\2/;ta;P;D'
A 200 100
B 300 600 700
C 400
0 голосов
/ 16 марта 2012

Используя sed:

Содержимое script.sed:

## First line. Newline will separate data, so add it after the content.
## Save it in 'hold space' and read next one.
1 {
    s/$/\n/
    h   
    b   
}

## Append content of 'hold space' to current line.
G

## Search if first char (\1) in line was saved in 'hold space' (\4) and add 
## the number (\2) after it.
s/^\(.\)\( *[0-9]\+\)\n\(.*\)\(\1[^\n]*\)/\3\4\2/

## If last substitution succeed, goto label 'a'.
ta

## Here last substitution failed, so it is the first appearance of the
## letter, add it at the end of the content.
s/^\([^\n]*\n\)\(.*\)$/\2\1/

## Label 'a'.
:a

## Save content to 'hold space'.
h

## In last line, get content of 'hold space', remove last newline and print.
$ {
    x   
    s/\n*$//
    p   
}

Запустите его как:

sed -nf script.sed infile

И результат:

A 200 100
B 300 600 700
C 400
0 голосов
/ 16 марта 2012

Используя awk, сортируя вывод внутри него:

awk '
  { data[$1] = (data[$1] ? data[$1] " " : "") $2 } 
  END { 
    for (i in data) { 
      idx[++j] = i 
    } 
    n = asort(idx); 
    for ( i=1; i<=n; i++ ) { 
      print idx[i] " " data[idx[i]] 
    } 
  }
' infile

Использование внешней программы sort:

awk '
  { data[$1] = (data[$1] ? data[$1] " " : "") $2 } 
  END { 
    for (i in data) { 
      print i " " data[i] 
    } 
  }
' infile | sort 

Для обеих команд вывод:

A 200 100
B 300 600 700
C 400
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...