punkish has asked for the wisdom of the Perl Monks concerning the following question:

Hi, I did a search and found a couple of nodes on array to hash conversions. Perhaps I didn't understand them correctly, but they do not seem to be the answer I am looking for. Here is my question --
# I have my ($fn, $ln, $age) = qw(Joe McCarty 89); # I want my %crazyperson = ( 'fn' => 'Joe', 'ln' => 'McCarty', 'age' => 89);
is there an easy, quick, standard way of doing this?
A related question -- if I have a variable $name, how do I get the string after the $, that is, 'name' in this case? In other words, how do I get the name a of variable instead of the value of the variable? Many thanks for any help.

Replies are listed 'Best First'.
Re: another 'array to hash' question
by tcf22 (Priest) on Dec 10, 2003 at 14:32 UTC
    Normally doing this is not good practice. If you need the variable names, then you should most likely use a hash.

    Here is an example of using an array to build a hash, which may help you, based on the title of your post.
    #!/usr/bin/perl -w use strict; use Data::Dumper; my @keys = qw( fn ln age ); my @values = qw( Joe McCarty 89 ); my %hash; @hash{@keys} = @values; print Dumper \%hash;

    - Tom

      y'know... this might work in my above code example. Thanks for this.
Re: another 'array to hash' question
by Abigail-II (Bishop) on Dec 10, 2003 at 14:40 UTC
    if I have a variable $name, how do I get the string after the $, that is, 'name' in this case?

    That's a silly question. Suppose there was a magical function that just did that. Suppose the magical function is called mushroom. Then you would have:

    my $name_of_var = mushroom $name; print $name_of_var; # prints 'name'.
    There would be no gain. You could as well have typed:
    my $name_of_var = 'name';
    after all, if you know which variable to get the name of, you already have the name. It's like phoning someone to ask his/her phone number.

    Furthermore, what if the variable is $foo {bar} () -> [3], what should this magical function return?


      >>if I have a variable $name, how do I get the string after the
      >>$, that is, 'name' in this case?
      >That's a silly question

      thanks ;-).

      I guess I asked that stemming from my original question about converting an array to a hash with array vars as hash key names. But, mostly the problem stems from my not clearly understanding how to deal with variable variables in perl. I have read a few diatribes here and there (Mark Jason Dominus wrote at length about the evils of variable variables), but don't really know how to avoid, work around, or do better.

      Sure, the way you put it, it is silly... after all, if I know the var's name then why run mushroom against the var to find out its name... however, look at the converse side -- I have to know the var's name to be able to run mushroom against it to find out its name... but what if I didn't know the var's name and wanted to find out? what if the var was a var? What if a robot is dialing a lot of phone numbers for me, and at any given time I want to find out what number I am currently talking to, and I don't have that lcd dial thingy that tells me the number I have dialed?

      Any pointers to reading lucid descriptions of dealing with variable variables in perl would be greatly appreciated.

      Many thanks.

        Any pointers to reading lucid descriptions of dealing with variable variables in perl would be greatly appreciated.
        In short, you don't. Why is it that so many people want to use symbolic references in Perl (because that's what it is)? You don't have symbolic references in C. You don't have symbolic references in Java. You don't have symbolic references in many, many languages. And I don't get the impression people programming in Java or C regulary ask how to get the name of a variable, or how to use a value as a variable.
        but what if I didn't know the var's name and wanted to find out?
        How could you? How can you have a variable, and not have its name?
        what if the var was a var?
        What else could a var be than a var? A rose is a rose is a rose is a rose.

        Note also that if you do

        @array = ($var1, $var2, $var3);
        then the elements of the array contain (copies of) the values pointed to by $var1, $var2 and $var3.


Re: another 'array to hash' question
by davido (Cardinal) on Dec 10, 2003 at 17:17 UTC
    The title of your node is "another 'array to hash' question", yet you ask:

    # I have my ($fn, $ln, $age) = qw(Joe McCarty 89); # I want my %crazyperson = ( 'fn' => 'Joe', 'ln' => 'McCarty', 'age => 89);

    ...which has to do with a list of scalars, not an array. It seems like you're asking "How do I convert a list of scalar variables and their values into a hash of keys (by the same names) and values?"

    Perhaps this is all you really need:

    my %crazyperson; @crazyperson{'fn', 'Joe', 'ln'} = qw/Joe McCarty 89/;

    ...which uses a hash slice.

    On the other hand, the question goes on to imply that you need to look up the symbol name of a variable. Which implies that you're trying to do something with symbolic references. Maybe, in that case, it would be easier to start out with the symbol names, and coerce them into scalar variable names, and use them as hash key names. But the whole thing sounds like madness, which is one of the best reasons for avoiding symbolic references in the first place. Of course another good reason for avoiding symbolic references is, for example:

    $name = "Ted"; while ( my $line = <DATA> ) { chomp $line; my ( $symbol, $value ) = split /,/, $line; ${$symbol} = $value; } print $name, "\n"; __DATA__ name,Frank __OUTPUT__ Frank

    What you've now done is allowed an external source to define the name of a global scalar variable within your script. It happens in this case, that the external source (__DATA__) has a symbol called "name". You're now in trouble, because you alreay were using $name to hold "Ted". You've just clobbered that, and given $name the value "Frank" instead.

    By allowing an outside source free reign over names of global variables inside your script, you stand a pretty good chance of eventually allowing that outside source to clobber a variable you're already using for something else.

    Consider, for example, that you've set a flag variable called, "$is_valid_user". And unless the flag is 'true', the user is denied access to something dangerous. Well, what if that user is allowed, through the magic of symbolic references from outside sources, to hand your script a true value for $is_valid_user? Symbolic references open up this sort of issue, if used uncarefully.

    So the point is, not only is willy-nilly use of symbolic references "a road to madness", it's also insecure. And those are two very good reasons for not trying to get around the strictures imposed by the use strict; pragma.

    Update: You may be interested to know that the global symbol table (the names of all of your script's global variables) is, itself, held in a hash to which you have access. The hash is %::

    I mention this as an argument for convincing you that rather than using symbolic references to create and manipulate a bunch of entries in the %:: hash (your global symbol table), you should just use your own hash in the first place, avoiding pure scalar variables any time you start thinking, "Here's somewhere I need a symbolic ref." Using your own hash instead of your script's global symbol table hash, eliminates the potential for an outside source clobbering a variable you expect to be using for something else.

    There are legitimate needs for symbolic references, but those needs are quite advanced. You're almost always better off treating name/value pairs as hash elements from the outset rather than trying to create a symbolic reference out of the name.


Re: another 'array to hash' question
by caedes (Pilgrim) on Dec 10, 2003 at 14:31 UTC
    I'm pretty sure that what you're describing is both nearly impossible and something you wouldn't really want to do if you could. In the context of the rest of your code there is probably a much better way of solving the problem, but we can only guess what that is since you havn't provided much other code.

    Update: Now that I think about it, accessing the variable names as you descibe is really no different than hard coding the names in an array or just specifying the hash dirrectly. In all cases your still hard coding something, so the results will be the same.


      well, the simplest use of what I am looking for would be in converting a csv or tab delim var file into an array of hashes...

      my @a; while (<INFILE>) { my ($fn, $ln, $age) = split("\t", $_); # now convert this array to a hash and stuff it in the array push(@a, {'fn'=>$fn, 'ln'=>$ln, 'age'=>$age}); }

      DBI returns a nicely prepared array of hashes with fetchall_arrayref({}) and I was trying to "emulate" that while using text files. But, "if I could", I would probably find other uses as well.

        Does the CSV have a header line which describes the columns? I often do this
        chomp($headerline = <INFILE>); my @header = split(/\t/,$headerline);
        (although you could just define one relative to the code
        my @header = qw(fn ln age);
        Now when reading in the file
        while( <INFILE>) { chomp; my $c = 0; my @columns = split(/\t/,$_); push @a, { map { $header[$c++] => $_ } @columns }; }

        I really don't see why you shouldn't do it the way you have it coded here. And since you probably already know what the fields are, you can even skip the hash altogether. An array of arrays looks good to me.

        my @a; while (<INFILE>) { my @line = split /\t/; push @a, \@line; # Array of array references }

        Or even:

        my @a; push @a, ( split /\t/ ) while (<INFILE>); # array of arrays

        which provides a nice list context to put your input directly into an array. :)