Perl v5.28 can delete key-value slices

Perl v5.20 introduced key-value slices that worked on hashes and arrays. You could extract values by their keys or indices as well as assigning to those.

The key-value slice delete is way to extract the keys and values you want and delete them at the same time. You can destructively

A review of delete

The delete removes the element from the hash or array and returns it.

use v5.10;

my %hash = qw(
	Cat    Buster
	Dog    Addy
	Bird   Foghorn
	Lizard Godzilla
	);

my $removed_value = delete $hash{'Lizard'};
say "Removed $removed_value";
say Dumper( \%hash );

The delete removed the Lizard key and returned its value:

Removed Godzilla
$VAR1 = {
          'Bird' => 'Foghorn',
          'Dog' => 'Addy',
          'Cat' => 'Buster'
        };

A delete on a slice does the same thing. The @ before hash signifies multiple values (not an array!) and you know it’s a hash variable because the indexing uses {}:

use v5.10;
use Data::Dumper;

my %hash = qw(
	Cat    Buster
	Dog    Addy
	Bird   Foghorn
	Lizard Godzilla
	);

my @removed_values = delete @hash{ qw(Lizard Bird) };
say "Removed @removed_values";
say Dumper( \%hash );

The delete returns the values from the keys it deleted:

Removed Godzilla Foghorn
$VAR1 = {
          'Cat' => 'Buster',
          'Dog' => 'Addy'
        };

This works on arrays too even though the documentation says you shouldn’t use them. The “key” doesn’t necessarily disappear. Interior items become undef and items at the end disappear:

Removed Addy Godzilla
$VAR1 = [
          'Buster',
          undef,
          'Foghorn'
        ];

One of the “keys” (the one that was at the end) is apparently gone but the interior “key” is still present but now has an undef value. Maybe that works for you but I’m guessing your maintenance programmer won’t know that.

The key-value slice

The key-value slice extracts the keys and the values at the same time. It returns a list (maybe of zero items if the key does not exist):

use v5.20;

my %hash = qw(
	Cat    Buster
	Dog    Addy
	Bird   Foghorn
	Lizard Godzilla
	);

say join ' ', %hash{ qw(Bird Lizard) }

The output shows the keys and their values:

Bird Foghorn Lizard Godzilla

This works on an array and uses the indices as the keys and square braces to surround those keys. There’s still a % in front of the variable name to signify that it’s a key-value slice but you use the square brackets for the indices (Item 4. Understand what sigils are telling you.):

use v5.20;

my @array = qw(
	Buster
	Addy
	Foghorn
	Godzilla
	);

my @indices = ( 1, 3 );
my @sliced = %array[@indices];
say "@sliced";

Now the keys are the list indices. This can be useful when you don’t know ahead of time what the indices are but still need to match them up with their values:

1 Addy 3 Godzilla

This is certainly more palatable than computing the intermediate results and merging the indices later:

my @indices = ( 1, 3 );
my @values = @array[@indices];
my @sliced = zip( @indices, @values );

Destructive processing with key-value slices

Deleting a key-value slice removes the elements (sets them to undef if an array) and removes those key-values at the same time.

Suppose that show_items does some complicated and interesting task. It needs to know which value it is processing and what that value belongs to. The key-value delete provides the keys and values together and removes them from the things to process:

use v5.28;

my %hash_to_process = qw(
	Cat    Buster
	Dog    Addy
	Bird   Foghorn
	Lizard Godzilla
	);

my @items_to_process = qw(Bird Lizard);
process( delete %hash_to_process{ @items_to_process } )

sub process { say "Processing @_" }

Things to remember

  • A classic delete returns the value
  • A key-value delete returns both the key and the value
  • The % signifies a key-value slice for either a hash or an array