# perl help (foreach with %array)

**URL:** <https://boards.straightdope.com/t/perl-help-foreach-with-array/609920>\
**Category:** Factual Questions\
**Created:** [January 18, 2012, 7:00pm UTC](https://boards.straightdope.com/t/perl-help-foreach-with-array/609920 "2012-01-18T19:00:51Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![NoCoolUserName](https://avatars.discourse-cdn.com/v4/letter/n/5fc32e/32.png) [@NoCoolUserName](https://boards.straightdope.com/u/NoCoolUserName)\
**Post date:** [January 18, 2012, 7:00pm UTC](https://boards.straightdope.com/t/perl-help-foreach-with-array/609920/1 "2012-01-18T19:00:51Z")

</div>

My test code:

# cat test.pl

$list{‘one’} = ‘two’;

foreach $name (%list)  
{  
print "Old: $name, New: $list{$name}  
";  
}

What happens:

# perl test.pl

Old: one, New: two  
Old: two, New:

# 

My confusion: Why does foreach use ‘two’ for a second line of printout? There’s only one element in the array, isn’t there? I only want ‘one’ to map to ‘two’ but I’m getting a bogus mapping of ‘two’ to (blank).

---

<div class="post-metadata">

**Author:** ![Manduck](https://sea3.discourse-cdn.com/straightdope/user_avatar/boards.straightdope.com/manduck/32/256_2.png) [@Manduck](https://boards.straightdope.com/u/Manduck)\
**Post date:** [January 18, 2012, 7:06pm UTC](https://boards.straightdope.com/t/perl-help-foreach-with-array/609920/2 "2012-01-18T19:06:49Z")

</div>

I think when you access a hash like that, you get key-value pairs. What you want is something like:

foreach $key (keys %list)

etc

---

<div class="post-metadata">

**Author:** ![friedo](https://avatars.discourse-cdn.com/v4/letter/f/8edcca/32.png) [@friedo](https://boards.straightdope.com/u/friedo)\
**Post date:** [January 18, 2012, 7:24pm UTC](https://boards.straightdope.com/t/perl-help-foreach-with-array/609920/3 "2012-01-18T19:24:21Z")

</div>

> [@NoCoolUserName](#):
>
> My test code:
> 
> My confusion: Why does foreach use ‘two’ for a second line of printout? There’s only one element in the array, isn’t there? I only want ‘one’ to map to ‘two’ but I’m getting a bogus mapping of ‘two’ to (blank).

What you’ve got is a hash, not an array. In Perl, when you use a hash in a list context (such as the argument for a foreach loop) what you get back is a list of key/value pairs. So your loop is equivalent to

```auto

foreach $name ( 'one', 'two' ) { ... }

```

The first iteration looks up the key ‘one’ in the hash. The second iteration looks up the key ‘two’, which doesn’t exist, so you get blank output.

This is one of the many many many many many reasons why you should turn on ‘strict’ and ‘warnings’ whenever you’re writing Perl code. Here’s how to do it properly:

```auto

use strict;
use warnings;

my %list = ( one => 'two' );
# or you could say: my %list; $list{one} = 'two';

foreach my $name ( keys %list ) { 
    print "Old: $name, New: $list{$name}
";
}

```

Notice I’ve used the very handy ‘my’ keyword to scope variables to their enclosing block (or file in the case of %list). This is required under strict mode.

---

<div class="post-metadata">

**Author:** ![NoCoolUserName](https://avatars.discourse-cdn.com/v4/letter/n/5fc32e/32.png) [@NoCoolUserName](https://boards.straightdope.com/u/NoCoolUserName)\
**Post date:** [January 18, 2012, 11:20pm UTC](https://boards.straightdope.com/t/perl-help-foreach-with-array/609920/4 "2012-01-18T23:20:42Z")

</div>

Ignorance fought. Using the keyword “keys” is the bit I was missing.

Thanks!

And **friedo** , thanks for the advice, but heck, I first learned programing back in '67 or so when “structure” was what a building had, not what you used in your code. We used GOTO like there was no tomorrow. I’m too old (now) to learn another way. 🙂

---

<div class="post-metadata">

**Author:** ![Voyager](https://sea3.discourse-cdn.com/straightdope/user_avatar/boards.straightdope.com/voyager/32/133_2.png) [@Voyager](https://boards.straightdope.com/u/Voyager)\
**Post date:** [January 19, 2012, 1:29am UTC](https://boards.straightdope.com/t/perl-help-foreach-with-array/609920/5 "2012-01-19T01:29:37Z")

</div>

> [@NoCoolUserName](#):
>
> Ignorance fought. Using the keyword “keys” is the bit I was missing.
> 
> Thanks!
> 
> And **friedo** , thanks for the advice, but heck, I first learned programing back in '67 or so when “structure” was what a building had, not what you used in your code. We used GOTO like there was no tomorrow. I’m too old (now) to learn another way. 🙂

I learned in 1968, but there is a good reason to use strict mode. Perl is non-declarative, and if you don’t and have a typo in a variable name you will get odd results. Using strict will cause errors which will let you catch this more easily.

You have to be aware of the structure because if you my something in a while loop, say, and then try to use that variable outside, you will get a totally different variable. You’ll also get an error if strict is turned on. So. not much to do with structure, more getting to the level of FORTRAN declarations.

---

<div class="post-metadata">

**Author:** ![NoCoolUserName](https://avatars.discourse-cdn.com/v4/letter/n/5fc32e/32.png) [@NoCoolUserName](https://boards.straightdope.com/u/NoCoolUserName)\
**Post date:** [January 20, 2012, 10:54pm UTC](https://boards.straightdope.com/t/perl-help-foreach-with-array/609920/6 "2012-01-20T22:54:34Z")

</div>

Additional question (in case anyone is still watching this thread):

My variables actually have metacharacters in them, but I want them used as characters, not as wildcards:  
$one=‘one+x’;  
$two = ‘two’;  
$list{$one} = $two;

$line = “one+x”;  
$line =~ s/$one/$list{$one}/;  
Is there any way to make this happen other than putting a backslash in front of any possible metacharacter before the substitution?

Thanks again!

---

<div class="post-metadata">

**Author:** ![friedo](https://avatars.discourse-cdn.com/v4/letter/f/8edcca/32.png) [@friedo](https://boards.straightdope.com/u/friedo)\
**Post date:** [January 21, 2012, 1:13am UTC](https://boards.straightdope.com/t/perl-help-foreach-with-array/609920/7 "2012-01-21T01:13:49Z")

</div>

```auto

$line =~ s/\Q$one\E/$list{$one}/;

```

\Q and \E are delimiters for telling the regex engine to ignore interpolated regex metachars. See the ever-useful [perlre](http://perldoc.perl.org/perlre.html#Quoting-metacharacters) manpage.

---

<div class="post-metadata">

**Author:** ![NoCoolUserName](https://avatars.discourse-cdn.com/v4/letter/n/5fc32e/32.png) [@NoCoolUserName](https://boards.straightdope.com/u/NoCoolUserName)\
**Post date:** [January 22, 2012, 5:32pm UTC](https://boards.straightdope.com/t/perl-help-foreach-with-array/609920/8 "2012-01-22T17:32:34Z")

</div>

friedo, you rawk. I did look for what I needed on that page but wan’t clever enough to find it.
