in reply to Comparing a list to a tab delimited text file

G'day Azaghal,

Welcome to the Monastery.

In this sort of situation, it's best to advise us of both the size of the data and the size of available memory. You'll get very different answers for a 100Mb file and 8Gb memory vs. 8Gb file and 100Mb memory.

It looks like you've slurped your entire "tab delimited text file" (TSV) into what appears to be a global array, @lexiques. You are then processing every TSV record every time you do a search (for another global variable, $thewordimsearching). Using global variables is fraught with problems and should be avoided wherever possible. Processing the entire TSV repeatedly for every search is a very poor choice.

When working with tab- (or comma-, or pipe-, or whatever-) separated data, reach for Text::CSV in the first instance. This module is very easy to use and has been written specifically to handle this type of data. Except for maybe an academic exercise, this is not a wheel you should consider reinventing. If you also have Text::CSV_XS installed, it will run faster.

In the example code below, I show how to capture the TSV data once and then use it as many times as necessary. If the script is to be run multiple times, you might want to consider serialising the hash data using something like the builtin Storable module. If the TSV data exceeds your memory capacity, you could store the processed data in a database. These are just a couple of suggestions: you haven't supplied sufficient information about the data, your environment, or the intended usage, to do anything beyond making tentative guesses as to how you should best proceed.

Here's the dummy TSV file I used for my testing:

$ cat pm_1207122_data.tsv A A1 A2 A3 A4 A5 A6 B B1 B2 B3 B4 B5 B6 C C1 C2 C3 C4 C5 C6 D D1 D2 D3 D4 D5 D6 E E1 E2 E3 E4 E5 E6 F F1 F2 F3 F4 F5 F6

In the following example script, &initialise is run once to capture the TSV data, and &search is run as many times as you want. Note how the arguments are passed to the subroutines, including the use of references (\%tsv_data) so that only a single scalar is passed instead of a huge data structure. Also note the limited scope of @words, $tsv_file, and %tsv_data: they cannot be accessed directly outside of the anonymous block in which they are declared.

#!/usr/bin/env perl -l use strict; use warnings; use autodie; use Text::CSV; { my @words = 'A' .. 'I'; my $tsv_file = 'pm_1207122_data.tsv'; my %tsv_data; initialise($tsv_file, \%tsv_data); search($words[rand @words], \%tsv_data) for 1 .. 5; } sub initialise { my ($file, $data) = @_; open my $fh, '<', $file; my $csv = Text::CSV::->new({sep_char => "\t"}); while (my $row = $csv->getline($fh)) { $data->{$row->[0]} = [@$row[1..$#$row]]; } } sub search { my ($find, $data) = @_; print "$find: ", exists $data->{$find} ? "@{$data->{$find}}[3,4]" : '<not fou +nd>'; }

Here's the results of a couple of sample runs:

C: C4 C5 G: <not found> E: E4 E5 D: D4 D5 D: D4 D5
A: A4 A5 I: <not found> F: F4 F5 H: <not found> E: E4 E5

— Ken