Search code examples
perlhashtable

Need help on "Experimental keys on scalar is now forbidden" for `@a = keys { map { $_ => undef } @a }`


I wrote some code where I tried to make list members unique by converting the list to a hash and then using the keys of that hash as elements. This worked without complaint in Perl 5.18, but now fails in Perl 5.26:

@a = keys { map { $_ => undef } @a }

The error messages are

Experimental keys on scalar is now forbidden at ...
Type of arg 1 to keys must be hash or array (not anonymous hash ({})) at ...

I'd like to avoid creating a temporary hash variable for that purpose.

In perlfaq4 How can I remove duplicate elements from a list or array? there is a solution, but it uses a separate temporary variable:

my %hash   = map { $_, 1 } @array;
# or a hash slice: @hash{ @array } = ();
# or a foreach: $hash{$_} = 1 foreach ( @array );

my @unique = keys %hash;

#...
my %seen = ();
my @unique = grep { ! $seen{ $_ }++ } @array;

So how should I re-write the original code for newer perl?


Solution

  • On new enough Perls you can use postfix deref:

    @a = keys { map { $_ => undef } @a }->%*
    

    Older Perls will need an infix deref:

    @a = keys %{{ map { $_ => undef } @a }}
    

    Or you could use an anonymous sub to separate the generation from the deduplication:

    @a = sub { keys %{{@_}} }->( map { $_ => undef } @a )
    

    But all of this is unnecessary, because List::Util::uniq has been in core Perl since 5.8, which was released almost 23 years ago.