使用类似的列收集数据

时间:2012-03-16 07:37:09

标签: perl unix sed awk

我想从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 个答案:

答案 0 :(得分:3)

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已经存在:r中为$ 1,附加OFS $ 2 现有价值
  • 否则将其设置为$ 2
  • 的值

表达?如果为true:如果为false则为三元运算符。 有关详情,请参阅ternary operation

答案 1 :(得分:2)

你可以这样做,但是使用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

答案 2 :(得分:1)

不是特定于语言的。更像是伪代码,但这里的想法是:

- 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中,但这只是一种品味问题。

答案 3 :(得分:0)

使用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

答案 4 :(得分:0)

使用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

答案 5 :(得分:0)

这可能对您有用:

sort -sk1,1 file | sed ':a;$!N;s/^\([^ ]*\)\( .*\)\n\1/\1\2/;ta;P;D'
A 200 100
B 300 600 700
C 400