Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you treat hashes in arrays properly?

Tags:

perl

I've got an array of hashes:

my @questions = (
    {"Why do you study here?" => "bla"},
    {"What are your hobbies?" => "blabla"});

And I try to loop through it:

foreach (@questions) {
    my $key = (keys $_)[0];
    $content .= "\\section{$key}\n\n$_{$key}\n\n";
}

giving me

Use of uninitialized value in concatenation (.) or string at convert.pl line 44.

Where does the error come from?

like image 663
chaosflaws Avatar asked Feb 26 '14 15:02

chaosflaws


People also ask

How to access a hash inside an array Ruby?

In Ruby, the values in a hash can be accessed using bracket notation. After the hash name, type the key in square brackets in order to access the value.

How do you add a hash to an array in Ruby?

You are allowed to create an array of hashes either by simply initializing array with hashes or by using array. push() to push hashes inside the array. Note: Both “Key” and :Key acts as a key in a hash in ruby.

What is a hash vs array?

With arrays, the key is an integer, whereas hashes support any object as a key. Both arrays and hashes grow as needed to hold new elements. It's more efficient to access array elements, but hashes provide more flexibility.


2 Answers

$_{$key} looks up $key in the hash variable %_. The sigil $ at the beginning indicates that the type of the result is a scalar. It's the syntactic construct VAR{KEY} that determines that VAR must be a hash. Although $_ and %_ use the same symbol as a name, the different sigils make them unrelated variables.

You need to dereference the hash reference $_ into the underlying hash. The syntax for this is $_->{$key} or ${$_}{$key}.

See the reference tutorial for a more general presentation of the topic.

like image 118
Gilles 'SO- stop being evil' Avatar answered Sep 18 '22 10:09

Gilles 'SO- stop being evil'


Gilles already explained how to use your current data structure, but I would recommend that you use a different data structure altogether: a simple hash.

#!/usr/bin/perl

use strict;
use warnings;
use 5.010;

my %answers = (
    "Why do you study here?" => "bla",
    "What are your hobbies?" => "blabla"
);

while (my ($question, $answer) = each %answers) {
    say "Question: $question";
    say "Answer: $answer";
}

Output:

Question: Why do you study here?
Answer: bla
Question: What are your hobbies?
Answer: blabla

I find this easier to work with than an array of hashes, each of which only contains a single key/value pair.

If you want to iterate through the hash in a certain (non-sorted) order, there are a couple of options. The simplistic solution is to maintain an array of keys in the order you want to access them:

# In the order you want to access them
my @questions = ("What are your hobbies?", "Why do you study here?");

my %answers;
@answers{@questions} = ("blabla", "bla");

foreach my $question (@questions) {
    say "Question: $question";
    say "Answer: $answers{$question}";
}

Output:

Question: What are your hobbies?
Answer: blabla
Question: Why do you study here?
Answer: bla

Another option is to use Tie::IxHash (or the faster XS module Tie::Hash::Indexed) to access keys in insertion order:

use Tie::IxHash;

tie my %answers, "Tie::IxHash";

%answers = (
    "Why do you study here?" => "bla",
    "What are your hobbies?" => "blabla"
);

while (my ($question, $answer) = each %answers) {
    say "Question: $question";
    say "Answer: $answer";
}

Output:

Question: Why do you study here?
Answer: bla
Question: What are your hobbies?
Answer: blabla
like image 40
ThisSuitIsBlackNot Avatar answered Sep 19 '22 10:09

ThisSuitIsBlackNot