The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

# usage: intersect( [ARRAY REF], [ARRAY REF], ... )
# return: ARRAY REF
sub intersect {
	
	check_prototype(@_, '(\@)+');
	
	if(scalar(@_) < 2) {
		return $_[0];
	}
	
    my $set1 = shift;
    my $set2 = shift;
	my @remain_set = @_;
	
	# if set1 or set2 is empty
	if(is_empty($set1) or is_empty($set2)) {
		return [];
	}
	
    my $hash2;
    for (@$set2) {
        $hash2->{$_} = 1;
    }
	
	$set1 = unique($set1);
    
    my $intersect;
    for (@$set1) {
        push(@$intersect, $_) if($hash2->{$_});
    }
	
	if($intersect) {
		$intersect = intersect($intersect, @remain_set);
	}
	else {
		return [];
	}
	
	return $intersect;
}

# usage: union( [ARRAY REF], [ARRAY REF] )
# return: ARRAY REF
sub union {
	
	check_prototype(@_, '(\@)+');
	
	if(scalar(@_) < 2) {
		return $_[0];
	}
	
    my $set1 = shift;
    my $set2 = shift;
	my @remain_set = @_;
	
	$set1 = unique($set1);
	$set2 = unique($set2);
    
    my $hash1;
    my $union = $set1;
    for (@$set1) {
        $hash1->{$_} = 1;
    }
	
	for (@$set2) {
		push(@$union, $_) if(! $hash1->{$_});
	}
	
	$union = union($union, @remain_set);
	
	return $union;
}

# usage: complement( [ARRAY REF], [ARRAY REF] )
# return: ARRAY REF
# set1 - set2
sub setdiff {
	
	check_prototype(@_, '\@\@');
	
    my $set1 = shift;
    my $set2 = shift;
    
    my $hash2;
    foreach (@$set2) {
        $hash2->{$_} = 1;
    }
    
    my $diff;
    foreach (@$set1) {
        push(@$diff, $_) unless($hash2->{$_});
    }
    return $diff;
}

# usage: setequal( [ARRAY REF], [ARRAY REF] )
# return: 1|0
sub setequal {
	
	check_prototype(@_, '\@\@');
	
	my $set1 = shift;
	my $set2 = shift;
	
	my $unique_set1 = unique($set1);
	my $unique_set2 = unique($set2);
	my $union = union($set1, $set2);
	
	if(len($unique_set1) == len($unique_set2)
	   and len($unique_set1) == len($union)) {
		return 1;
	}
	else {
		return 0;
	}
}

# usage: is_element( [SCALAR], [ARRAY REF])
# return 0|1
sub is_element {
	
	check_prototype(@_, '$\@');
	
	my $item = shift;
	my $set = shift;
	
	for(my $i = 0; $i < len($set); $i ++) {
		if(is_numberic($set->[$i]) and is_numberic($item)
		   and abs($set->[$i] - $item) < EPS) {
			return 1;
		}
		elsif($set->[$i] eq $item) {
			return 1;
		}
	}
	return 0;
}

1;