【问题标题】:Unique elements in each file每个文件中的唯一元素
【发布时间】:2012-06-21 14:58:54
【问题描述】:

我有 4 个文件,想知道与其他文件中的元素相比,哪些元素不重叠(每个文件)。

文件 A

Vincy
ruby
rome

文件 B

Vincy
rome
Peter

文件 C

Vincy
Paul
alex

文件 D

Vincy
rocky
Willy

对 perl、python、shell、bash 中的一个衬里的任何建议。预期的输出是:

文件 A:ruby,文件 B:Peter,文件 C:PaulAlex 文件 D:rockyWilly

【问题讨论】:

  • 你希望这里的输出是什么?
  • @sven:我放弃了,这就是我发帖的原因。
  • @Sean:文件 A:ruby,文件 B:Peter,文件 C:Paul,Alex 文件 D:rocky,Willy
  • 所有这些文件都符合all elements are unique to each file的条件。
  • 我应该重新构建问题,我看到了我的错误和答案中的错误。

标签: python perl bash shell


【解决方案1】:

在问题澄清后编辑:所有文件中的唯一元素,以及它所在的文件:

cat File_A File_B File_C File_D |sort | uniq -u | while read line ; do file=`grep -l $line File*` ; echo "$file $line" ; done

编辑:

如果文件很大,这样做会更快:

#!/usr/bin/perl

use strict;
use autodie;

my $wordHash ;

foreach my $arg(@ARGV){
    open(my $fh, "<", $arg);
    while(<$fh>){
        chomp;
        $wordHash->{$_}->[0] ++;
        push(@{$wordHash->{$_}->[1]}, $arg);
    }
}

for my $word ( keys %$wordHash ){
    if($wordHash->{$word}->[0] eq 1){
        print $wordHash->{$_}->[1]->[0] . ": $word\n"
    }
}

执行为: myscript.pl filea fileb filec ... filezz

澄清之前的东西: 使用 shell 命令很容易。所有文件中的非重复元素

cat File_A File_B File_C File_D |sort | uniq -u

所有文件的独特元素

cat File_A File_B File_C File_D |sort | uniq

每个文件的唯一元素 (感谢@Dennis Williamson 编辑)

for line in File* ; do echo "working on $line" ; sort $line | uniq ; done

【讨论】:

  • 我不知道 uniq。我的工具箱里多了一个工具,谢谢。
  • 在 cmets 中查看所需的输出。 OP 似乎正在寻找仅出现在单个文件中的行,按文件分组。这些解决方案都没有。
  • 是的 - 在他不幸补充之前回答了
  • 他们移动球门柱时总是很有趣。
  • 不错。您应该取消引用"File*"(导致它在我的安装中失败)并输入最终的| sort 以获得有序输出。 +1。
【解决方案2】:

这是一个快速的 Python 脚本,可以对任意数量的文件执行您所要求的操作:

from sys import argv
from collections import defaultdict

filenames = argv[1:]
X = defaultdict(list)
for f in filenames:
    with open(f,'r') as FIN:
        for word in FIN:
            X[word.strip()].append(f)

for word in X:
    if len(X[word])==1:
        print "Filename: %s word: %s" % (X[word][0], word)

这给出了:

Filename: D word: Willy
Filename: C word: alex
Filename: D word: rocky
Filename: C word: Paul
Filename: B word: Peter
Filename: A word: ruby

【讨论】:

  • 此解决方案具有线性运行时间,因此它比其他答案中的 O(n²) 解决方案效率更高。
  • 你应该使用with来打开和关闭文件。
【解决方案3】:

热针:

import sys
inputs = {}
for inputFileName in sys.args[1:]:
  with open(inputFileName, 'r') as inputFile:
    inputs[inputFileName] = set([ line.strip() for line in inputFile ])
for inputFileName, inputSet in inputs.iteritems():
  print inputFileName
  result = inputSet
  for otherInputFileName, otherInputSet in inputs.iteritems():
    if otherInputFileName != inputFileName:
      result -= otherInputSet
  print result

虽然没试过;-)

【讨论】:

  • 我总是忘记with open!。就目前而言不正确,有书面语法错误。 sys.args 应该是 sys.argv
  • @Hooked:对于大量文件,这个也更糟糕——文件数量是二次方的。您的解决方案是唯一一个在输入大小(所有输入文件的组合大小)中纯线性的解决方案。
  • @Hooked:嗯,是唯一的一个。 Perl 解决方案也是纯线性的。 :)
【解决方案4】:

带 cmets 的 Perl 单行可读版本:

perl -nlwe '     
    $a{$_}++;     # count identical lines with hash
    push @a, $_;  # save lines in array
    if (eof) { push @b,[$ARGV,@a]; @a=(); }   # at eof save file name and lines
    }{ # eskimo operator, executes rest of code at end of input files
    for (@b) { 
        print shift @$_;                      # print file name
        for (@$_) { print if $a{$_} == 1 };   # print unique lines
    }
' file{A,B,C,D}.txt

注意:eof 用于每个单独的输入文件。

复制/粘贴版本:

perl -nlwe '$a{$_}++; push @a, $_; if (eof) { push @b,[$ARGV,@a]; @a=(); } }{ for (@b) { print shift @$_; for (@$_) { print if $a{$_} == 1 } }' file{A,B,C,D}.txt

输出:

filea.txt
ruby
fileb.txt
Peter
filec.txt
Paul
alex
filed.txt
rocky
Willy

注意:这比预期的要棘手,我相信有办法让它更漂亮,但我现在先发布这个,看看我是否可以清理它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-10
    • 1970-01-01
    • 2013-01-02
    • 1970-01-01
    • 1970-01-01
    • 2019-09-16
    • 2017-11-09
    • 2019-09-19
    相关资源
    最近更新 更多