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

What is the best way to do this? I need to assign values from a split, but I'd like to throw away values that are meaningless or unwanted.

I can think of a few other ways to do this, but these were the best two I came up with.
#!/usr/bin/perl -w use strict; # Use undef hash values for unneeded fields my @fields = ( 'FIRSTNAME', 'LASTNAME', 'PHONE', undef, # Useless data undef, # Useless data undef, # Useless data 'FAX', undef, # Useless data 'CITY', 'STATE', ); # Use dummy key for unneeded fields my @fields2 = ( 'FIRSTNAME', 'LASTNAME', 'PHONE', 'DUMMY', # Useless data 'DUMMY', # Useless data 'DUMMY', # Useless data 'FAX', 'DUMMY', # Useless data 'CITY', 'STATE', ); while (<DATA>) { chomp; my (%record, %record2); # Using undef keys; requires disabling warnings # about uninitialized values in hash slice no warnings; @record{@fields} = split(/\t/, $_); print "1) First Name: $record{FIRSTNAME}, State: $record{STATE}\n" +; # Using dummy key, then deleting it use warnings; @record2{@fields2} = split(/\t/, $_); delete $record2{'DUMMY'}; print "2) First Name: $record2{FIRSTNAME}, State: $record2{STATE}\ +n"; } print "\n---------------\nDone.\n"; exit; __DATA__ Bill Davis 999-888-7777 KH101 1 1 999-888-7770 19 +65 Chantilly VA Bob Rogers 999-777-8888 KH101 1 1 999-777-8880 19 +53 Dallas TX Jim Dawson 999-787-8787 KH101 1 1 999-787-8787 19 +72 San Diego CA Harry Jones 999-878-7878 KH101 1 1 999-878-7870 1 +963 Chicago IL John Black 999-778-7788 KH101 1 1 999-778-7788 19 +36 Topeka KS
Which of these is the better solution, or does someone (I hope) have another solution that would be best?

Impossible Robot

Replies are listed 'Best First'.
Re: Ignoring values in a hash slice assignment
by grep (Monsignor) on Feb 28, 2002 at 21:54 UTC
    What about using an array list slice on your hash slice?
    my @fields = ( 'FIRSTNAME', 'LASTNAME', 'PHONE', 'FAX', 'CITY', 'STATE', );
    and then
    @record{@fields} = (split(/\t/, $_))[0,1,2,6,8,9];
    UPDATE: thx to converter for pointing out my goof-up

    grep
    grep> grep clue /home/users/*
      Thanks, grep (and dragonchild who made a similar suggestion).

      Using an array slice on the split was one of the other ways I considered, but my actual field list is much longer (over 70 fields in all), and I didn't want to maintain two long lists.

      I could generate the second list programmatically, but I figured that would be even more complicated that my two solutions. (Of course, it is very possible that I was wrong.)

      Impossible Robot
        Actually I was going to add 'creating the list programmatically' as an additional suggestion. The great thing is, if you do it right, your data structure is factored out to 1 place, so you only have to make changes in 1 place as you make changes. I think if you follow this you'll be happier in the long run.

        grep
        grep> grep clue /home/users/*
Re: Ignoring values in a hash slice assignment
by dragonchild (Archbishop) on Feb 28, 2002 at 21:55 UTC
    Instead of thinking about what to get rid of, think about what to keep.
    my @desired_fields = (1, 3, 5 .. 7, 9); my @field_names = qw(A B C D E F); my %stuff; while (<DATA>) { chomp; @stuff(@field_names} = (split /\t/, $_)[@desired_fields]; }

    ------
    We are the carpenters and bricklayers of the Information Age.

    Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

Re: Ignoring values in a hash slice assignment
by petral (Curate) on Feb 28, 2002 at 22:05 UTC
    Or even:
    my @fields = qw(A B C D E F); my %indices; @indices{@fields} = 0 .. $#fields; . . . my @chosen = qw(A B D F); . . . @rec{@chosen} = (split/\t/)(@indices{@chosen});
      p
Re: Ignoring values in a hash slice assignment
by seattlejohn (Deacon) on Mar 01, 2002 at 08:01 UTC
    Just for the fun of it I had to try doing this with my favorite function, map. These two lines seem to do the trick:
    my $i = -1; %record = map {defined($fields[++$i]) ? ($fields[$i] => $_) : ()} (spl +it /\t/, $_);

    but I would not recommend using such an abomination in production code!

    Now if only I could think of a good way to get rid of that temporary variable, which feels so profoundly un-Perlish...

Re: Ignoring values in a hash slice assignment
by impossiblerobot (Deacon) on Mar 01, 2002 at 16:53 UTC
    An update:

    After working through the great responses I got, and testing various options, here's where I am:

    • My first solution (using undef as key values for fields I didn't want) wasn't doing what I thought it was. Although Perl warned (when warnings were turned on) about assigning to an uninitialized value in a hash slice, it also quite happily initialized those keys to an empty string (like it does with other undefined scalars in similar situations). So both of my solutions were really doing the same thing: assigning to a dummy key (named '' or 'DUMMY', respectively). The only problem was that I wasn't deleting the dummy key in the first solution. :-)
    • There were no real surprises with using an array slice with my hash slice (as suggested by almost everyone), but there was one significant downside: I was replacing two lines of very readable code with up to five lines of much less readable code, and I feared for those who would have to maintain this after me.
    • So, unless someone comes up with a better idea, I will be using my second solution. I think that in general a combination of the various answers I received might be a better solution, but for this project, simplicity wins.
    Thanks to everyone who I haven't thanked yet (petral and seattlejohn) and I'm still open to more suggestions. :-)

    Impossible Robot
      Ok. You're just not thinking it through. You say that you have a list of some 70 fields, some of which may be needed and others not. Given how you presented your original question, you're storing this list of fieldnames in an array, putting 'DUMMY' for the fields you wish to ignore.

      That, my friend, is a maintainer's nightmare.

      1. You don't ever say what the field is you're ignoring
      2. You don't say WHY you're ignoring that field
      3. It isn't easy to change which fields you're ignoring without researching into what fields exist
      4. It also isn't easy to change which order the fields exist in.

      So, we need some way of abstracting out which fields are there. Then, we need a way of identifying which fields we actually want. Lastly, we need a way of making sure that this information (which will become quite large) doesn't impact our main program.

      Enter "Modular Design". Let's create a module where we store some data about what fields we want. Let's also create a few functions that allow us to talk about various aspects (or attributes) of each field.

      Now, you don't need a full-blown OO implementation of this. That would be too much work and too unwieldy to manage. However, you can do a very nice Exporter implementation of this. Something along the lines of: