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

Glorius and patient Monks...

I haven't work with Perl for a while so this is one of the questions that will have simple answer and I get to do a head slap after I read the asnwer.

I'm attempting to populate a combo box using a hash, which in turn is populated by a text file. If the text file has one value per key separated by a tab, then the following code works great to create the hash. Populating the combo box goes swimmingly from there.

my ($hash, $file) = @_; my $dir = "C:\\Program Files\\ArcMan\\"; if(-e $dir.$file){ open(TABLE, $dir.$file); while(<TABLE>){ my($key, $value) = split(/\t/,$_); $$hash{$key} = $value; } close (TABLE); }else{ ErrorDialog("$file does not exist. ", $!); } #delete last eol return in text file so it does not appear #in hash delete $$hash{"\n"};

However, when there are multiple values per key the process breaks down. No surprise since the code is set up to split the first tab it finds.

ex: Name 'bob' 'sue' 'dave'. where Name is the key with three values separated by tabs. When values are separated by spaces then I get 'bob sue dave' as a single value.

So I'm stumped. Thanks in advance.

Replies are listed 'Best First'.
Re: creating hashes
by CountZero (Bishop) on Jan 09, 2008 at 06:50 UTC
    If the key - values lines are set up as follows key\tvalue1 value2 value3 (in other words a tab separates the key from the values and the values are separated by spaces, you could split on generic whitespace: my($key, @values) = split(/\s/,$_); and then store a reference to the @values array in your hash: $$hash{$key} = \@values;

    One other comment: you might wish to chomp the result from your <TABLE> to get rid of the EOL character(s).

    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

      My suggestion indeed is to "use a hash of anon arrays...where 'bob', 'sally', 'sue' are entries 0, 1, 2 of teh anon array" and of course the anon array is the value linked to each key in your hash.

      You therefore would need to de-reference the anon-array reference to get at the names. How you put these in your combo box is a bit beyond me. Personally, I would use two combo-boxes, one with your hash keys which, once you pick one entry, dynamically loads the names related to that key and puts them in the second combo-box. A clear case for an AJAX-empowered web-page if you ask me ;-)

      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

      Intriguing.....one concern, how would this work with multpile key/value pairs, say 20 pairs with 20 values each..(not extreme by any means). For the combo box I will need to access the keys and values discretely. Having an array ref, as I understand it and I could be wrong, means the entire value set is a single array entry at array[0].

      In your proposal you get Name 'bob sally sue',

      It got me thinking, and perhaps this is just restating your idea (and i apologize if it is) that I should either be using an array outright instead of a hash or use a hash of anon arrays...where 'bob', 'sally', 'sue' are entries 0, 1, 2 of teh anon array. Hmmmm....

      Thanks for the chomp tip...head slap...:)

      Graff's original suggestion works great...sorry, head slap, just too rusty here to see it and thought it had to be more complicated. The following code populates the combobox

      sub PopulateComboBox { my $hash = shift; foreach my $key(keys (%$hash)){ $MainWindow->FilterList->Add($key); foreach (@{$$hash{$key}}) { $MainWindow->FilterList->Add($_); } } $MainWindow->FilterList->SetCurSel(0); }

      many thanks

Re: creating hashes
by graff (Chancellor) on Jan 09, 2008 at 07:32 UTC
    ex: Name 'bob' 'sue' 'dave'. where Name is the key with three values separated by tabs. When values are separated by spaces then I get 'bob sue dave' as a single value.

    So I'm stumped.

    Me too. Are you saying that having "bob sue dave" as a single value in the combo box would be wrong? Or would it be right? If it's wrong, what sort of combo box is it, exactly, and in what way does it provide for offering/selecting multiple values relating to a given key string?

    If having all the tab-delimited names concatenated in the one hash value would be right, you just need to change how you do the split:

    ... my($key, $value) = split(/\t/,$_,2); # might also need to do this: $value =~ s/\t/ /g; $$hash{$key} = $value; ...
    The third arg in the split() call says "stop splitting when you get to the second item", which means, in effect, that everything after the first tab gets returned as one string, and no further splitting is done.

    (And do heed the advice in the earlier reply: chomp lines inside the while loop before splitting, and skip empty lines within the loop, instead of assigning them to the hash -- i.e.   next unless $key and $value;