【问题标题】:merge multiple lines into single line by value of column按列的值将多行合并为单行
【发布时间】:2011-09-15 15:04:11
【问题描述】:

我有一个非常大的制表符分隔的文本文件。文件中的许多行对于文件中的一列具有相同的值。我想把它们放在同一行。例如:

a foo
a bar
a foo2
b bar
c bar2

运行脚本后应该变成:

a foo;bar;foo2
b bar
c bar2

如何在 shell 脚本或 Python 中执行此操作?

谢谢。

【问题讨论】:

  • 相似的行是连续的吗? (所有 A 行都在 B 行之前,B 在 C 之前,等等)如果是这样,这是相当微不足道的。如果没有,那就稍微不那么琐碎了。你试过什么?

标签: python perl split


【解决方案1】:

用 awk 你可以试试这个

{   a[$1] = a[$1] ";" $2 }
END { for (item in a ) print item, a[item] }

因此,如果您将此 awk 脚本保存在一个名为 awkf.awk 的文件中,并且如果您的输入文件是 ifile.txt,请运行该脚本

awk -f awkf.awk ifile.txt | sed 's/ ;/ /'

sed 脚本是去掉前导的 ;

希望对你有帮助

【讨论】:

    【解决方案2】:
    from collections import defaultdict
    
    items = defaultdict(list)
    for line in open('sourcefile'):
        key, val = line.split('\t')
        items[key].append(val)
    
    result = open('result', 'w')
    for k in sorted(items):
        result.write('%s\t%s\n' % (k, ';'.join(items[k])))
    result.close()  
    

    未测试

    【讨论】:

    • 什么是“from collections import defaultdict”和“items = defaultdict(list)”?
    • @Jianguo : "defaultdict" 不是内置类型,所以你必须导入它,它在 "collections" 中。 docs.python.org/library/…
    【解决方案3】:

    用 Python 2.7 测试:

    import csv
    
    data = {}
    
    reader = csv.DictReader(open('infile','r'),fieldnames=['key','value'],delimiter='\t')
    for row in reader:
        if row['key'] in data:
            data[row['key']].append(row['value'])
        else:
            data[row['key']] = [row['value']]
    
    writer = open('outfile','w')
    for key in data:
        writer.write(key + '\t' + ';'.join(data[key]) + '\n')
    writer.close()
    

    【讨论】:

    • Traceback(最近一次调用最后):文件“transform.py”,第 16 行,在 writer.write(key+'\t'+string.join(data[key],' ;')+'\n') 文件“/usr/lib/python2.6/string.py”,第 318 行,在 join return sep.join(words)
    • 我也在 Python 2.6 中对此进行了测试,没有出现错误。我确实从错误消息中收集到我可以将代码 string.join(data[key],';') 简化为 ';'.join(data[key])
    • @Jianguo 至于你的错误,列出的代码会产生这个错误吗?我根据您在问题中列出的源数据粘贴创建了 infile。
    • Traceback(最近一次调用最后一次):文件“transform.py”,第 18 行,在 writer.write(key+'\t'+ ';'.join(data[key] )+'\n') TypeError: sequence item 0: expected string, NoneType found
    • @Jianguo 我从错误消息中注意到您可能在 Linux 上运行,因此我也使用 Python 2.4 和 2.6 进行了测试。对我来说仍然没有错误。由于您的错误编号在第 18 行,而测试代码只有 15 行,因此我需要查看更多代码来调试此错误。此行之前的 key 和 data 对象的内容是什么?
    【解决方案4】:

    一种 Perl 方法:

    #!/usr/bin/perl 
    use strict;
    use warnings;
    use Data::Dumper;
    
    open my $fh, '<', 'path/to/file' or die "unable to open file:$!";
    my %res;
    while(<$fh>) {
        my ($k, $v) = split;
        push @{$res{$k}}, $v;
    }
    print Dumper \%res;
    

    输出:

    $VAR1 = {
          'c' => [
                   'bar2'
                 ],
          'a' => [
                   'foo',
                   'bar',
                   'foo2'
                 ],
          'b' => [
                   'bar'
                 ]
        };
    

    【讨论】:

      【解决方案5】:
      #! /usr/bin/env perl
      
      use strict;
      use warnings;
      
      # for demo only
      *ARGV = *DATA;
      
      my %record;
      my @order;
      while (<>) {
        chomp;
        my($key,$combine) = split;
      
        push @order, $key unless exists $record{$key};
        push @{ $record{$key} }, $combine;
      }
      
      print $_, "\t", join(";", @{ $record{$_} }), "\n" for @order;
      
      __DATA__
      a foo
      a bar
      a foo2
      b bar
      c bar2
      

      输出(制表符转换为空格,因为 Stack Overflow 会破坏输出):

      一个 foo;bar;foo2
      酒吧
      c bar2

      【讨论】:

        【解决方案6】:
        def compress(infilepath, outfilepath):
            input = open(infilepath, 'r')
            output = open(outfilepath, 'w')
            prev_index = None
        
            for line in input:
                index, val = line.split('\t')
                if index == prev_index:
                    output.write(";%s" %val)
                else:
                    output.write("\n%s %s" %(index, val))
            input.close()
            output.close()
        

        未经测试,但应该可以工作。如有任何疑问,请发表评论

        【讨论】:

        • “infilepath”和“outfilepath”应该是inputfile和outputfile还是目录?
        • 它们是字符串,分别是输入文件和输出文件的路径。
        • 我刚刚做了一个编辑,应该使代码更节省内存
        • 文件"./transform.py", line 7 def compress("/home/jianguo/software/tanghaibao-goatools-bfce032/data" "/home/jianguo/software/tanghaibao-goatools- bfce032/数据"): ^
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-08-31
        • 1970-01-01
        • 2022-01-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-02-18
        相关资源
        最近更新 更多