Adding to or removing from an array you're iterating over is a bad idea. If you create a loop over two elements (indices 0 and 1) and, on the first iteration, remove one element, what will happen on the second iteration?
An alternate approach would be to build up a third data structure to hold the difference of the two sets. I think perlfaq4 has the right idea. The code might be (warning, untested!):
my @AoH_all = (
{
name => "Bill",
id => 1,
},
{
name => "Mike",
id => 3
});
my @AoH_one = (
{
name => "Bill",
id => 1,
} );
my %keep_ids = map { $_->{id} => 1 } @AoH_all;
delete @keep_ids{ map { $_->{id} } @AoH_one };
my @difference = grep { exists $keep_ids{ $_->{id} } } @AoH_all;
Update: two typos fixed.