http://www.perlmonks.org?node_id=887211

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

Hi Monks,
$string="1:one;2:two;3:three"; %hash;

I want hash like 1=>one, 2=>two .. using map in single line.

Kindly help on please

Replies are listed 'Best First'.
Re: Create a hash by spliting string
by Utilitarian (Vicar) on Feb 09, 2011 at 14:25 UTC
    You have the basics of it already. you can split on a regular expression, so a character class that included both colon ":" and semi-colon ";" would split your string into a list of 6 elements.

    At this point, knowing that any list with an even number of elements can be assigned to a hash is important because that's how you'd complete the task, simply by assigning the output of the split to %hash

    print "Good ",qw(night morning afternoon evening)[(localtime)[2]/6]," fellow monks."

      Whereas I, being forever distrustful of data, would split the string on semicolons, and then, in a loop, split each piece separately.   And, my code would verify that each of these splits generated exactly two pieces, and it would croak if ever it did not.   So, this would not only accomplish the task of splitting the string, but also confirm that it is well-formed.

      Yup... guess I’m a Perl Dork.

        Hardly a dork, after all verifying your data is valid before throwing it into a structure is the correct thing to do. However I suspect our Anonymous friend isn't writing production code here

        print "Good ",qw(night morning afternoon evening)[(localtime)[2]/6]," fellow monks."
Re: Create a hash by spliting string
by CountZero (Bishop) on Feb 09, 2011 at 15:03 UTC
    Use the magical split_and_store_in_hash function!

    What, your version of Perl doesn't have it? In that case you will have to start writing it yourself or look into other functions. It may be that it is named a bit different.

    Come back here once you have shown some effort and we will gladly help you.

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

      try the below code,
      $string="1:one;2:two;3:three"; %hash=grep(/\w+/, split(/(;|:)/, $string));
      Arivu

        This question seems to be popping up all over the forum here, and people are making it harder than it has to be.

        Perl knows how to turn a flat list into a hash. For example, you can say the following (and it will work):

        my %hash = ( 1 => 'one', 2 => 'two', 3 => 'three', );

        And since the => operator is just a special kind of comma (oversimplification), the code above is pretty much the same as this:

        my %hash = ( '1', 'one', '2', 'two', '3', 'three', );

        And that is exactly the same as this:

        my %hash = ( '1', 'one', '2', 'two', '3', 'three' );

        And wouldn't you know it... that works too, as it should.

        By now the light bulb really ought to be switching on. You can assign a flat list to a hash. Hmm, I wonder how we can convert the string presented by the original poster to a flat list...

        split still comes in handy. But the fact is, it's the only tool you need, and you need it only once. The regexp you used has the defect of using capturing parenthesis, which in the context of a split is often undesirable (unless you really do want to keep the delimiters). You could have used non-capturing parens, as in /(?:;|:)/, but you actually don't need to constrain your alternation at all; there's nothing beyond the simple alternation of /;|:/ But for single-character alternation I prefer just using a character class as in /[;:]/. However, it turns out that in the OP's example string, all of the characters he wants to keep are "word" characters (\w), which means all his delimiters are non-word characters (\W). So the split expression could be further simplified to /\W/. Splitting on non-words will give us a flat list that looks like qw/1 one 2 two 3 three/.

        Putting it all together, the line that does all the work will look like this:

        %hash = split /\W/, $string;

        No need for grep, no need for nested splits, no need for map... just toss out the delimiters and you've got a flat list which can be assigned to a hash.


        Dave

Re: Create a hash by spliting string
by Anonymous Monk on Feb 09, 2011 at 13:59 UTC
    Where is your code? Where is your attempt?

    Oh I forgot for a second that you're taking a test. Ask your teacher :)