#!/usr/bin/env perl use strict; use warnings; my %data = ( A => [qw{ant bee cat dog eel fly gnu hog}], B => [qw{ant cat eel gnu}], C => [qw{bee dog fly hog}], D => [qw{cat fly ant}], E => [qw{ant dog gnu}], F => [qw{gnu bee}], G => [qw{eel hog}], H => [qw{zoo}], I => [qw{}], ); my %temp; for my $set (keys %data) { my @elems = @{$data{$set}}; @elems = ('') unless @elems; for my $elem (@elems) { push @{$temp{$elem}}, $set; } } my (%venn, %seen); for my $elem (sort keys %temp) { my @sets = @{$temp{$elem}}; my $glob_expr = '{' . join(',', @sets) . '}'; for my $i (1 .. $#sets) { $glob_expr .= '-{,' . join(',', @sets[$i .. $#sets]) . '}'; } for my $key (glob($glob_expr)) { next if $key =~ /([^-]+)(?=.*?\1)/; $key =~ y/-/-/s; $key =~ s/(?:^-|-$)//g; $key = join '-', sort split /-/, $key; push @{$venn{$key}}, $elem unless $seen{$key}{$elem}++; } } # DEMO: Output my $fmt = "%-7s %s %s\n"; { no warnings 'qw'; printf $fmt, qw{Sets # Elements}; printf $fmt, qw{---- - --------}; } printf $fmt, $_, 0+@{$venn{$_}}, "@{$venn{$_}}" for sort keys %venn; #### Sets # Elements ---- - -------- A 8 ant bee cat dog eel fly gnu hog A-B 4 ant cat eel gnu A-B-D 2 ant cat A-B-D-E 1 ant A-B-E 2 ant gnu A-B-E-F 1 gnu A-B-F 1 gnu A-B-G 1 eel A-C 4 bee dog fly hog A-C-D 1 fly A-C-E 1 dog A-C-F 1 bee A-C-G 1 hog A-D 3 ant cat fly A-D-E 1 ant A-E 3 ant dog gnu A-E-F 1 gnu A-F 2 bee gnu A-G 2 eel hog B 4 ant cat eel gnu B-D 2 ant cat B-D-E 1 ant B-E 2 ant gnu B-E-F 1 gnu B-F 1 gnu B-G 1 eel C 4 bee dog fly hog C-D 1 fly C-E 1 dog C-F 1 bee C-G 1 hog D 3 ant cat fly D-E 1 ant E 3 ant dog gnu E-F 1 gnu F 2 bee gnu G 2 eel hog H 1 zoo I 1 #### #!/usr/bin/env perl use strict; use warnings; my %data = ( A => [qw{ant bee cat dog eel fly gnu hog}], B => [qw{ant cat eel gnu}], C => [qw{bee dog fly hog}], D => [qw{cat fly ant}], E => [qw{ant dog gnu}], F => [qw{gnu bee}], G => [qw{eel hog}], H => [qw{zoo}], I => [qw{}], ); my (%venn, %temp); for my $set (sort keys %data) { my @elems = @{$data{$set}}; @elems = ('') unless @elems; for my $elem (@elems) { push @{$temp{$elem}}, $set; } } for my $elem (keys %temp) { my @sets = @{$temp{$elem}}; for my $i (0 .. $#sets) { my @subsets = @sets[$i .. $#sets]; my $key = shift @subsets; push @{$venn{$key}}, $elem; for my $set (@subsets) { $key .= "-$set"; push @{$venn{$key}}, $elem; } } } my $fmt = "%-7s %s %s\n"; { no warnings 'qw'; printf $fmt, qw{Sets # Elements}; printf $fmt, qw{---- - --------}; } for my $sets (sort keys %venn) { printf $fmt, $sets, 0+@{$venn{$sets}}, join ' ', sort @{$venn{$sets}}; } #### Sets # Elements ---- - -------- A 8 ant bee cat dog eel fly gnu hog A-B 4 ant cat eel gnu A-B-D 2 ant cat A-B-D-E 1 ant A-B-E 1 gnu A-B-E-F 1 gnu A-B-G 1 eel A-C 4 bee dog fly hog A-C-D 1 fly A-C-E 1 dog A-C-F 1 bee A-C-G 1 hog B 4 ant cat eel gnu B-D 2 ant cat B-D-E 1 ant B-E 1 gnu B-E-F 1 gnu B-G 1 eel C 4 bee dog fly hog C-D 1 fly C-E 1 dog C-F 1 bee C-G 1 hog D 3 ant cat fly D-E 1 ant E 3 ant dog gnu E-F 1 gnu F 2 bee gnu G 2 eel hog H 1 zoo I 1