perl - 在 perl 中创建集合

标签 perl set hash

我正在尝试在三个输入条件下查找集合(参见附图)。

例如:

C1:

I
want
to
create
a
set
in
perl
with
some
values

C2:

how
to
create
set
these
values

C3:

a
set
in
perl
with
values
like
these

会产生一个像这样的集合图:

enter image description here

我知道如何针对每种情况以笨拙的方式做到这一点:

use warnings;
use strict; 

open my $C1, '<', 'C1.txt';
open my $C2, '<', 'C2.txt';
open my $C3, '<', 'C3.txt';

my (%c1_vals, %c2_vals, %c3_vals);
$c1_vals{$_}++ while(<$C1>);
$c2_vals{$_}++ while(<$C2>);
$c3_vals{$_}++ while(<$C3>);


my $c1_c2_count = 0;
my $c1_c3_count = 0;
my $c1 = 0;
my $total = 0;
my $all = 0;

for my $val (keys %c1_vals){
    $total++;
    $c1++ if not $c2_vals{$val} and not $c3_vals{$val};
    $c1_c2_count++ if $c2_vals{$val} and not $c3_vals{$val};
    $c1_c3_count++ if $c3_vals{$val} and not $c2_vals{$val};
    $all++ if $c2_vals{$val} and $c3_vals{$val};
}
print "c1 total = $total\n";
print "c1 = $c1\n";
print "c1 + c2  = $c1_c2_count\n";
print "c1 + c3 = $c1_c3_count\n";
print "c1+c2+c3 = $all\n";

c1 total = 11
c1 = 4
c1 + c2  = 2
c1 + c3 = 4
c1+c2+c3 = 1

但我想知道是否有一种更简单的方法可以使用子例程来执行此操作,该子例程从 @ARGV 读取每个文件并计算每个文件集。

我已经做到了这一点,但想不出一种优雅的方法来做到这一点:

parse($_) foreach @ARGV;

my %total;

sub parse {
    my $file = shift;
    open my $list, '<', $file or die "Can't read file '$file' [$!]\n";
    while (<$list>) {
        chomp;
        $total{$_}++;
    }
}

如有任何帮助,我们将不胜感激!

更新

为了清楚起见,我想找到所有 3 个数据集(总共 7 个)的所有交集(维恩图中的所有数字)。我不想使用模块,因为我想将其构建为一个更大的程序,而不需要太多更改。

最佳答案

只要将其保持在 32-64 组以下,使用按位算术可能会更容易:

my %c_vals;
$c_vals{$_} |= 1 while(<$C1>);
$c_vals{$_} |= 2 while(<$C2>);
$c_vals{$_} |= 4 while(<$C3>);

my $total = values %c_vals;
my $c1 = grep { $_ & 1 } values %c_vals;
my $c1_c2_count = grep { ($_ & 3) == 3 } values %c_vals;
my $c1_c3_count = grep { ($_ & 5) == 5 } values %c_vals;
my $all = grep { $_ == 7 } values %c_vals;

print "c1 total = $total\n";
print "c1 = $c1\n";
print "c1 + c2  = $c1_c2_count\n";
print "c1 + c3 = $c1_c3_count\n";
print "c1+c2+c3 = $all\n";

...

my @count_in_set;
foreach my $val (values %c_values) {
    $count_in_set[$val]++;
}
for (my $i=1; $i<=7; $i++) {
    printf "Count in set %03b: %d\n", $i, $count_in_set[$i];
}

一般情况下:

my %vals;
my $n = 0;
foreach my $file (@ARGV) {
    open my $fh, '<', $file;
    $vals{$_} |= 1 << $n for <$fh>;
    $n++;
}
my @count_in_set;
foreach my $val (values %c_values) {
    $count_in_set[$val]++;
}
for (my $i=1; $i<=$#count_in_set; $i++) {
    printf "Count in set %0*b: %d\n", $n, $i, $count_in_set[$i];
}

关于perl - 在 perl 中创建集合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30085644/

相关文章:

perl - 无法在未引用的引用上调用 “capture2”方法

forms - 在 Perl 脚本中混合 POST 值

java - 如何不考虑表中的重复值

go - 如何在仅最后几个字节发生变化的golang数据中有效地散列(SHA 256)

c++ - 在 main 之后立即导致堆栈溢出的代码

perl - 如何在 IMAP 邮件主题中搜索非 ASCII 文本

perl - Selenium headless 无法在带有 Perl 的 CentOS 7 上运行, "no display specified"

javascript - 在 node.js 中验证一个集合是否为空

PHP-EWS 2010,如何设置 IsRead 标志

Java:如何在哈希数组映射特里树(HAMT)插入期间执行哈希冲突缓解?