Blog

Arrays und Hashes in Scheibchen

28.07.2023 // Renée Bäcker

Dieser Post gehört nicht zur Perl5.38-Serie

Die sozialen Medien haben mir den Blogpost von Packy Anderson über die Weekly Challenge #226 in die Zeitleiste gespült. Die Aufgabe 1 lautet

You are given a string and an array of indices of same length as string.

Write a script to return the string after re-arranging the indices in the correct order.

Example 1

Input: $string = 'lacelengh', @indices = (3,2,0,5,4,8,6,7,1)
Output: 'challenge'

Example 2

Input: $string = 'rulepark', @indices = (4,7,3,1,0,5,2,6)
Output: 'perlraku'

Die Zahlen in dem Array @indices geben also an, wo die Buchstaben stehen sollen (beginnend mit der Position 0): das c ist der dritte Buchstabe in dem String. Schauen wir uns das dritte Element des Arrays an, so steht dort die 0. Also muss das c an der Position 0 im Ergebnis stehen usw.

Das hat in mir direkt Gedanken zu einem Thema ausgelöst, das vermutlich völlig unterschätzt ist: Slices.

Damit kann man aus Hashes und Arrays Teilstücke – eben Scheibchen – herausbekommen, ohne Schleifen oder ähnliches nutzen zu müssen. Bevor wir uns die Slices genauer anschauen, ein kurzer Ausflug in die sogenannten Sigils ($, @ und %):

Mit dem Sigil $ sagt man aus, dass ein einzelner Wert genutzt wird. Bei den Variablen trifft man das $ bei den Skalarvariablen an. In diesen wird genau ein Wert gespeichert: Eine Zahl, ein String, eine Referenz. Das Sigil @ bedeutet, dass es um mehrere Werte geht und das % zeigt an, dass es um eine Schlüssel-Wert-Zuordnung geht.

In der Aufgabe kann man diese Sigils auch gut erkennen:

$string = 'lacelengh';
@indices = (3,2,0,5,4,8,6,7,1)

In der Skalarvariablen wird ein String gespeichert und in dem Array mehrere Zahlen.

Möchten wir das 3. Element aus dem Array bekommen, möchten wir ja genau 1 Sache bekommen, also ändert sich das Sigil von @ zu $.

$drittes_element = $indices[2];

Da die Zählung des Index' bei 0 beginnt, ist der Index des dritten Elements die 2. Auch wenn wir 1em Element etwas zuweisen wollen, ändert sich das Sigil:

$indices[2] = 10;

Bei Hashes sieht es ähnlich aus:

%essen = (
    morgens => 'Brot',
    mittags => 'Falafel',
    abends  => 'Chips',
);

$abendessen = $essen{abends};
$essen{morgens} = 'Ei';

Das bedeutet, immer wenn man das $ sieht, geht es um genau 1 Sache. Die Datenscheibe ist also sehr dünn.

Soll die Datenscheibe etwas dicker sein, man also mehrere Werte haben möchte, dann kann man mit den anderen Sigils arbeiten. Sollen das 3. und das 5. Element aus dem Array ausgegeben werden, dann kann man das so machen:

say "@indices[2,4]";

Die Ausgabe das mit ist 0 4.

Genauso kann man diese Slices auch bei der Zuweisung verwenden:

@indices = (1,2,3,4);
@indices[1,3] = (5,10);  # @indices = (1,5,3,10)

Dieses Verhalten kann man jetzt wunderbar für die Lösung der oben genannten Aufgabe aus der Weekly Challenge nutzen:

#!/usr/bin/perl

use v5.10;

my $string  = 'rple';
my @indices = (2,0,3,1);

my @sorted_chars;
@sorted_chars[@indices] = split //, $string;
say @sorted_chars;

Da wir über use v5.10 automatisch auch strict aktivieren, müssen wir das Array @sorted_chars deklarieren.

Mit dem split in der nachfolgenden Zeile teilen wir den Ausgangsstring in die einzelnen Buchstaben auf. Und jetzt schauen wir mal kurz was die Zuweisung eingentlich aussagt:

@sorted_chars[2,0,3,1] = ('r','p','l','e');

Wenn wir die Indizes und die Buchstaben nach den Indizes sortiert hinschreiben würden, wäre das

@sorted_chars[0,1,2,3] = ('p','e','r','l');

Schön, oder?

Bei Hashes kann man auch mit Slices arbeiten: Wenn man die Werte zu mehreren Schlüsseln haben möchte. Was muss man dann machen?

Richtig, das Sigil ändert sich zu @, weil wir ja mehrere Werte haben wollen. Also bei dem Hash von oben:

@morgens_abends = @essen{'morgens','abends'};
# @morgens_abends = ('Brot','Chips');

@essen{'morgens','abends'} = ('Spiegelei','Brot');
# %essen = (
#    morgens => 'Spiegelei',
#    mittags => 'Falafel',
#    abends  => 'Brot',
# );

Und wenn man aus Arrays oder Hashes als Datenscheibe ein Schlüssel-Wert-Zuordnung haben möchte, dann muss man das Sigil % nutzen:

my @indices = (3,1,0,2);
my %map = %indices[1,3];

# %map = (
#    1 =>  1,
#    3 =>  2,
# );

my %essen = (
    morgens => 'Brot',
    mittags => 'Falafel',
    abends  => 'Chips',
);

my %morgens_abends = %essen{'morgens','abends'};

# {
#    abends  =>  "Chips",
#    morgens =>  "Brot",
# }

Man sieht, dass man mit Slices eleganten Code schreiben kann und über die Sigils erhält man auch immer Informationen darüber, was als Ergebnis gewünscht ist.


Am Ende noch: Herzlichen Glückwunsch an Mohammad Sajid Anwar, Initiator der Weekly Challenge zur Auszeichnung mit dem White Camel Award. Du hast es verdient!


Permalink: