splitting to a hashref

Discussion in 'Perl Misc' started by Keith, Apr 3, 2012.

  1. Keith

    Keith Guest

    I'm getting myself all confused - nothing new there.

    I'm building a data structure something like this (greatly
    simplified):

    my %company;
    ..
    ..
    $company{company_code} = {
    classes => [ split ('/',
    $record->{class_codes}) ]
    }

    The incoming data field 'class_codes' is structured like this:

    "CLASS1/CLASS2/CLASS3/CLASS7/CLASS9"

    This means my data structure ends up with an entry called 'classes'
    which holds an array reference to a list of class codes. What I'd
    really like is that entry to hold a hash reference where each key is a
    class code, and the corresponding value is 'Y' (for example).

    I did try changing that line to read:
    classes => { split ('/',
    $record->{class_codes}) => 'Y' }

    But that gives me this:
    $VAR1 = {
    'classes' => {
    'CLASS9' => 'Y',
    'CLASS3' => 'CLASS7',
    'CLASS1' => 'CLASS2'
    }
    };

    I'm missing something fundamental about slices here, I guess. Please
    help!
    Keith, Apr 3, 2012
    #1
    1. Advertising

  2. Keith

    Tim McDaniel Guest

    In article
    <>,
    Keith <> wrote:
    >I'm building a data structure something like this (greatly
    >simplified):
    >
    >my %company;
    >.
    >.
    >$company{company_code} = {
    > classes => [ split ('/',$record->{class_codes}) ]
    >}


    (I removed massive whitespace)

    >The incoming data field 'class_codes' is structured like this:
    >
    >"CLASS1/CLASS2/CLASS3/CLASS7/CLASS9"
    >
    >This means my data structure ends up with an entry called 'classes'
    >which holds an array reference to a list of class codes. What I'd
    >really like is that entry to hold a hash reference where each key is
    > a class code, and the corresponding value is 'Y' (for example).
    >
    >I did try changing that line to read:
    > classes => { split ('/', $record->{class_codes}) => 'Y' }
    >
    >But that gives me this:
    >$VAR1 = {
    > 'classes' => {
    > 'CLASS9' => 'Y',
    > 'CLASS3' => 'CLASS7',
    > 'CLASS1' => 'CLASS2'
    > }
    > };
    >
    >I'm missing something fundamental about slices here, I guess. Please
    >help!


    Perl isn't quite as slicy as you'd like. Also, => is not a special
    pairing operator; it's just a fancy-pants way of writing ",". So the
    guts are equivalent to

    { split ('/', $record->{class_codes}), 'Y' }

    which evaluates to a list of just the class codes, followed by one
    "Y", so it's just

    { 'CLASS1', 'CLASS2', 'CLASS3', 'CLASS7', 'CLASS9', 'Y' }

    {...}, or other uses of lists where it's expecting a hash, then does
    the pairing, using alternating elements of the list as key and value
    in that order. That produces your result (out of alphabetical order
    because Perl hashes do that).

    Perl doesn't provide the pairing you want, so you have to do it by
    hand:

    classes => { map { $_, 'Y' } split ('/', $record->{class_codes}) }

    (Most people would actually write "$_ => 'Y'", but I want to emphasize
    to you that => really IS a comma, and what's important is having
    key followed by value.)

    {} have two different meanings here. {} in map{} are code block
    delimiters, like if{} or sub{}. It's the outer {...} that make an
    anonymous hash ref.

    Or you could assign to a temp array and do a foreach, or do something
    involving
    @classes{@classes_array} = ('Y') x scalar @classes_array;
    but that map version is really simplest.

    --
    Tim McDaniel,
    Tim McDaniel, Apr 3, 2012
    #2
    1. Advertising

  3. Keith

    ccc31807 Guest

    On Apr 3, 11:42 am, Keith <> wrote:
    > I'm getting myself all confused - nothing new there.


    Do it in small, simple steps, like this. Test each function separately
    to see that it does what you expect. There are more sophisticated ways
    to do this (e.g., Data::Dumper, Text::parseWords, etc.) but this will
    do what you want.

    #! perl
    use strict;
    use warnings;
    my (%in_data, %out_data);
    open_file_and_build_in_data();
    munge_in_data_to_out_data();
    test_hashes();
    write_out_data();
    exit(0);

    open_file_and_build_in_data
    {
    open IN, '<', 'in_data.dat' or die "$!";
    while (<IN>)
    {
    chomp;
    my ($val1, $val2, $val3 ...) = split(/\/\, $));
    my $in_data{$val1} = {
    val2 => $val2,
    val3 => $val3,
    ... };
    }
    close IN;
    }
    munge_in_data_to_out_data
    {
    foreach my $key (keys %in_data)
    {
    #iterate through the keys building your out data
    }
    }
    test_hashes
    {
    #just for sanity's sake
    foreach my $key1 (keys %in_data)
    {
    print "$key1 =>\n";
    foreach my $key2 (keys %{$in_data{$key1}})
    {
    print " $key2 => $in_data{$key1}{$key2}\n";
    }
    }
    foreach my $key1 (keys %out_data)
    {
    print "$key1 =>\n";
    foreach my $key2 (keys %{$out_data{$key1}})
    {
    print " $key2 => $out_data{$key1}{$key2}\n";
    }
    }
    }
    }
    write_out_data
    {
    open OUT, '>', 'out_data.dat' or die "$!":
    foreach my $key1 (keys %out_data)
    {
    foreach my $key2 (keys %{$out_data{$key1}})
    {
    print OUT qq($key1,$out_data{$key1}{$key2} ... \n);
    }
    close OUT;
    }
    }
    ccc31807, Apr 3, 2012
    #3
  4. Keith

    Willem Guest

    Keith wrote:
    ) This means my data structure ends up with an entry called 'classes'
    ) which holds an array reference to a list of class codes. What I'd
    ) really like is that entry to hold a hash reference where each key is a
    ) class code, and the corresponding value is 'Y' (for example).
    )
    ) I did try changing that line to read:
    ) classes => { split ('/',
    ) $record->{class_codes}) => 'Y' }
    )
    ) But that gives me this:
    ) $VAR1 = {
    ) 'classes' => {
    ) 'CLASS9' => 'Y',
    ) 'CLASS3' => 'CLASS7',
    ) 'CLASS1' => 'CLASS2'
    ) }
    ) };
    )
    ) I'm missing something fundamental about slices here, I guess. Please
    ) help!

    I have no idea what this has to do with slices, but if you want to
    transform an array into a hash, you need to use 'map':

    classes => { map { $_ => 'Y' } split '/', ... }

    Which will do what you wanted.


    SaSW, Willem
    --
    Disclaimer: I am in no way responsible for any of the statements
    made in the above text. For all I know I might be
    drugged or something..
    No I'm not paranoid. You all think I'm paranoid, don't you !
    #EOT
    Willem, Apr 4, 2012
    #4
  5. # I want to answer this !

    my %company;
    my $record = {};

    $record->{class_codes} = "CLASS1/CLASS2/CLASS3/CLASS7/CLASS9";
    $company{company_code} = { classes => Doit($record->{class_codes}) };

    use Data::Dumper; print Dumper(\%company);

    sub Doit {
    local $_=[[split/\//,$_[0]],{}];
    for (my($i,$j)=(0,1);$i<=$#{$_->[0]};$i+=2,$j+=$i) {
    exists $_->[0][$j] ? ($_->[1]{$_->[0][$i]}=$_->[0][$j] ):(
    $_->[1]{$_->[0][$i]} = 'Y' ) }
    $_->[1]
    }
    George Mpouras, Apr 4, 2012
    #5
  6. # Sorry , you need this one

    my %company;
    my $record = {};

    $record->{class_codes} = "CLASS1/CLASS2/CLASS3/CLASS7/CLASS9";
    $company{company_code} = { classes => eval{my$H; $H->{$_}='Y' foreach
    split/\//,$record->{class_codes};$H} };

    use Data::Dumper; print Dumper(\%company);
    George Mpouras, Apr 4, 2012
    #6
  7. Keith

    Tim McDaniel Guest

    In article <jlhog4$6ig$>,
    George Mpouras <> wrote:
    ># Sorry , you need this one
    >
    >my %company;
    >my $record = {};
    >
    >$record->{class_codes} = "CLASS1/CLASS2/CLASS3/CLASS7/CLASS9";
    >$company{company_code} = { classes => eval{my$H; $H->{$_}='Y' foreach
    >split/\//,$record->{class_codes};$H} };
    >
    >use Data::Dumper; print Dumper(\%company);


    If I may comment:

    Use of whitespace and indentation can REALLY help readability. I'm
    sorry, but I think the above is a good entry in the Obfuscated Perl
    Contest.

    $record->{class_codes} = "CLASS1/CLASS2/CLASS3/CLASS7/CLASS9";
    $company{company_code} = {
    classes => eval {
    my $H;
    $H->{$_}='Y' foreach split /\//, $record->{class_codes};
    $H
    }
    };
    use Data::Dumper; print Dumper(\%company);

    We had a discussion in the past few weeks about how to put code blocks
    inside expressions. One major opinion is "don't". But if you're
    going to do it, I think "do { ... }" is better than "eval { ... }",
    because if anything dies inside, "eval" will swallow the error unless
    you code to expose it (and you need to be more careful about that
    depending on the version of Perl).

    Looking at that, I still prefer

    $company{company_code} = {
    classes => { map { $_, 'Y' } split /\//, $record->{class_codes} }
    };

    And
    @{$company{company_code}{classes}}[split /\//, $record->{class_codes}] =
    ('Y') x length $record->{class_codes};
    is too silly and too obscure.

    --
    Tim McDaniel,
    Tim McDaniel, Apr 4, 2012
    #7
  8. Keith

    Keith Guest

    On Apr 4, 5:43 pm, (Tim McDaniel) wrote:

    > $company{company_code} = {
    >     classes => { map { $_, 'Y' } split /\//, $record->{class_codes}}


    My thanks to all who explained this so clearly. I've got it now, and
    as a pennance, I ahall learn all about the uses of the 'map' command!
    Keith, Apr 5, 2012
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. penguinista

    hashref strange side effects

    penguinista, Dec 23, 2004, in forum: Perl Misc
    Replies:
    3
    Views:
    117
    penguinista
    Dec 24, 2004
  2. bill

    Equality of hashref objects

    bill, Feb 4, 2005, in forum: Perl Misc
    Replies:
    7
    Views:
    130
    Anno Siegel
    Feb 5, 2005
  3. Sam
    Replies:
    6
    Views:
    149
    Anno Siegel
    Jun 15, 2005
  4. Sam
    Replies:
    1
    Views:
    81
    Ron Savage
    Aug 25, 2005
  5. Replies:
    6
    Views:
    138
    Brian McCauley
    May 12, 2006
Loading...

Share This Page