#!/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;