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

Hello monks. I learned how to use Tie::DBI a long time ago, and found a snippet of code that fit perfectly into a script I was writing. This code throws a "Can't use an undefined value as a HASH reference..." when I use it in my new script, but works perfectly fine as it is. Seems odd to me, can't figure out why it works, but not when placed in my script.

So the snippet of code I used is this:
use Tie::DBI; use List::Compare; tie %h,'Tie::DBI',{db => 'mysql:db', table => 'table', key => 'k', user => 'root', password => 'rootpass', CLOBBER => 1}; %day = ('the' => '1', 'tuesday' => '2', 'wednesday' => '3'); $lc = List::Compare->new([keys %day],[keys %h]); @intersections = $lc->get_intersection; foreach $intersection (@intersections) { print $intersection, "\n"; print $h{$intersection}{value}, "\n"; } exit;
In my script, the code looks like this:
my %count; #tie hash to the MySQL DB tie my %h,'Tie::DBI',{db => 'mysql:db', table => 'table', key => 'k', user => 'root', password => 'rootpass', CLOBBER => 1}; #split @titles by word, then to-lower, then remv special chars my @intersections; my $lc; foreach my $title (@titles) { my @words = split(" ", $title); foreach my $word (@words) { $word =~ tr/A-Z/a-z/; $word =~ s/[^a-zA-Z0-9]*//g; $count{$word}++; print $word, "\n"; } } $lc = List::Compare->new([keys %count],[keys %h]); @intersections = $lc->get_intersection; foreach my $intersection (@intersections) { print $intersection, "\n"; print $h{$intersection}{value}, "\n"; }
The error happens on the line:
print $h{$intersection}{value}, "\n";

The MySQL db is structured like this:

id|k |value --+---------+-------------- # |theword |1 (word count)
Also, in my script '@titles' contains sentences that will be split by word into a hash.

The first snippet of code returns

the 20

Thanks in advance, I'm honestly expecting a really stupid bit of something I overlooked, but any advice would be welcome. Thank you. **EDIT** Updated based on philipbailey's comment. Moved the list comparison out of the for loop. Still getting undefined.

Replies are listed 'Best First'.
Re: Tie::DBI works in one script... not the other
by philipbailey (Curate) on May 18, 2015 at 23:08 UTC

    It seems that you want to show values (and their counts) that appear both in the database and in plain text input data. You process that data word by word, but the assignment to @intersections happens anew on each iteration. Previous assignments are lost and assignment occurs whether or not you find a match. So the final content of @intersections is that of the last word processed, and presumably, for your input data, there is no match for the last word.

    I do not have an installed copy of List::Compare to hand, and the documentation doesn't say, but perhaps, even in a list context, it does an explicit return undef which would match the behaviour you see. Use Data::Dumper or similar to confirm what the data is.

    Consider pushing your data to @intersections.

      Also, Dumper did this:
      2015 $VAR1 = '2015'; 3 $VAR1 = '3'; a $VAR1 = 'a'; against $VAR1 = 'against'; all $VAR1 = 'all'; an $VAR1 = 'an'; and $VAR1 = 'and'; angeles $VAR1 = 'angeles'; are $VAR1 = 'are'; at $VAR1 = 'at'; atlanta $VAR1 = 'atlanta'; back $VAR1 = 'back'; be $VAR1 = 'be'; been $VAR1 = 'been'; bulls $VAR1 = 'bulls'; by $VAR1 = 'by'; clippers $VAR1 = 'clippers'; coaches $VAR1 = 'coaches'; coaching $VAR1 = 'coaching'; confirmed $VAR1 = 'confirmed'; contract $VAR1 = 'contract'; deandre $VAR1 = 'deandre'; doc $VAR1 = 'doc'; end $VAR1 = 'end'; far $VAR1 = 'far'; for $VAR1 = 'for'; free $VAR1 = 'free'; from $VAR1 = 'from'; future $VAR1 = 'future'; game $VAR1 = 'game'; had $VAR1 = 'had'; have $VAR1 = 'have'; hawks $VAR1 = 'hawks'; he $VAR1 = 'he'; here $VAR1 = 'here'; his $VAR1 = 'his'; i $VAR1 = 'i'; in $VAR1 = 'in'; irving $VAR1 = 'irving'; is $VAR1 = 'is'; james $VAR1 = 'james'; johnson $VAR1 = 'johnson'; jordan $VAR1 = 'jordan'; kevin $VAR1 = 'kevin'; kyrie $VAR1 = 'kyrie'; left $VAR1 = 'left'; los $VAR1 = 'los'; loves $VAR1 = 'loves'; making $VAR1 = 'making'; mcmenamin $VAR1 = 'mcmenamin'; mod $VAR1 = 'mod'; nba $VAR1 = 'nba'; now $VAR1 = 'now'; of $VAR1 = 'of'; on $VAR1 = 'on'; out $VAR1 = 'out'; play $VAR1 = 'play'; playoffs $VAR1 = 'playoffs'; points $VAR1 = 'points'; post $VAR1 = 'post'; reminder $VAR1 = 'reminder'; rivers $VAR1 = 'rivers'; rockets $VAR1 = 'rockets'; rules $VAR1 = 'rules'; says $VAR1 = 'says'; season $VAR1 = 'season'; series $VAR1 = 'series'; so $VAR1 = 'so'; take $VAR1 = 'take'; that $VAR1 = 'that'; the $VAR1 = 'the'; their $VAR1 = 'their'; they $VAR1 = 'they'; this $VAR1 = 'this'; throws $VAR1 = 'throws'; to $VAR1 = 'to'; today $VAR1 = 'today'; tony $VAR1 = 'tony'; two $VAR1 = 'two'; votes $VAR1 = 'votes'; wall $VAR1 = 'wall'; warriors $VAR1 = 'warriors'; washington $VAR1 = 'washington'; what $VAR1 = 'what'; will $VAR1 = 'will'; winning $VAR1 = 'winning'; with $VAR1 = 'with'; year $VAR1 = 'year';
      I don't understand how those values are undefined...
        None of the code you've posted so far uses Dumper, so seeing all this output from Dumper doesn't help much, since we can't tell what's being Dumped.

        If you haven't tried using the perl debugger on this yet (putting perl -d at the start of the command line when you run your script), that's probably what you should do next. Set a break point at the line that causes the error, so that the debugger stops and prompts for input from you when it reaches (but has not yet tried to execute) that line.

        When you reach the breakpoint, look at the value of $intersection, and confirm whether or not your hash has a matching key. (According to the error message, it doesn't). Then figure out why $intersection has the value that you see, and/or why the hash doesn't have that as a key.

      Thanks for the reply. I updated my post. So to explain a little bit further, in my sql table, the key is the word, and the value is the number of times it appears in the rest of the titles. A count of all duplicates, basically. So my database already has a bunch of words.