in reply to Re^2: Can't access data stored in Hash - help!
in thread Can't access data stored in Hash - help!

Hello again, corcra,

I’m glad to have been of help.

If I understand you correctly, you now want read the data headings, say:

Field: 0 5 6 7 8 File 1: ['CHROM', ... 'SAMPLE_1A', 'SAMPLE_1B', 'SAMPLE_2A', 'SAMPLE_2 +B'] File 2: ['CHROM', ... 'SAMPLE_1', 'SAMPLE_2', 'SAMPLE_3']

and have the script deduce that File 1 data in fields 5 and 6 should each be compared to File 2 field 5, File 1 data in fields 7 and 8 should each be compared to File 2 field 6, and so on.

That makes the logic more complex, but I don’t know why you think this will be difficult to do line-by-line? Most of the added logic comes before the big while loop:

... my $header1 = <$in1>; <$in2>; my @heads1 = split /\s*,\s*/, $header1; my $index = 5; my %index_map; for (@heads1) { $index_map{$index++} = $1 + 4 if /SAMPLE_(\d+)/; } print $header1; while (my $line1 = <$in1>) { my @fields1 = get_fields($line1); defined(my $line2 = <$in2>) or die "Data missing in file '$file2': $!"; my @fields2 = get_fields($line2); my @out = @fields1; for my $i (5 .. $#fields1) { if ($fields1[$i] ne 'REF') { my $j = $index_map{$i}; $out[$i] = $fields2[$j] if exists $fields2[$j] && $fields2[$j] ne 'REF'; } } @out = map { "'$_'" } @out; print '[', join(', ', @out), "]\n"; } ...

The main addition is a hash (%index_map) to keep track of the correspondences between the fields in File 1 and the matching fields in File 2.

Hope that helps,

Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Replies are listed 'Best First'.
Re^4: Can't access data stored in Hash - help!
by corcra (Initiate) on Aug 10, 2014 at 14:46 UTC

    Hi Athanasius, Hope you are well and thank you for all of your help so far. Unfortunately I still have not been able to get the code working as I want it to and I was hoping you could have one further look at the code I am running. The format of my input files has changed slightly but I don't think this will affect the code too much.

    File 1 CHROM POS REF ALT VARIANT_LIST 209T-D 459T-D 644T-D + 94T-D 99T1-D 99T2-D 99T3-D 99T4-D 99T5-D ['MT', '1010', 'G', 'A', 'A', 'REF', 'A', 'A', 'REF', 'A', 'A', 'A', ' +A', 'A'] ['MT', '2962', 'C', 'T', 'T', 'REF', 'T', 'T', 'T', 'T', 'T', 'T', 'T' +, 'T'] ...
    File 2 CHROM POS REF ALT VARIANT_LIST 209H-D 459H-D +644H-D 94H-D 99H-D ['MT', '1010', 'G', 'A', 'A', 'REF', 'REF', 'REF', 'REF', 'REF'] ['MT', '2962', 'C', 'T', 'T', 'REF', 'REF', 'T', 'REF', 'T'] ....
    Again I want to compare 99T1, 99T2, 99T3, 99T4 and 99T5 of File1 with 99H of file 2. The output I want looks like
    CHROM POS REF ALT VARIANT_LIST 209T-D 459T-D 644T-D + 94T-D 99T1-D 99T2-D 99T3-D 99T4-D 99T5-D ['MT', '1010', 'G', 'A', 'A', 'REF', 'A', 'A', 'REF', 'A', 'A', 'A', ' +A', 'A'] ['MT', '2962', 'C', 'T', 'T', 'REF', 'T', 'REF, 'T', 'REF', 'REF', 'RE +F', 'REF', 'REF']
    (because the same letter at the same position in File 1 and File 2 should output REF, and if REF is found at that position in file 2, just output letter from File 1) The code I am currently running is:
    #!/usr/local/bin/perl use strict; use warnings; my $file1 = shift; my $file2 = shift; open(my $in1, '<', $file1) or die "Cannot open file '$file1' for reading: $!"; open(my $in2, '<', $file2) or die "Cannot open file '$file2' for reading: $!"; my $header1 = <$in1>; <$in2>; my @heads1 = split "\t", $header1; my $index = 5; my %index_map; for (@heads1) { $index_map{$index++} = $1 + 4 if m/^(\d+)/; } print $header1; while (my $line1 = <$in1>) { my @fields1 = get_fields($line1); defined(my $line2 = <$in2>) or die "Data missing in file '$file2': $!"; my @fields2 = get_fields($line2); my @out = @fields1; for my $i (5 .. $#fields1) { my $j = $index_map{$i}; if ($fields1[$i] ne 'REF') { $out[$i] = $fields2[$j] if exists $fields2[$j] && $fields2[$j] ne 'REF'; } } @out = map { "'$_'" } @out; print '[', join(', ', @out), "]\n"; } close $in2 or die "Cannot close file '$file2': $!"; close $in1 or die "Cannot close file '$file1': $!"; sub get_fields { my ($line) = @_; chomp $line; my @fields = split "\t", $line; s{ ^ \[? ' }{}x for @fields; s{ ' \]? $ }{}x for @fields; return @fields; }
    which should work but the output is
    CHROM POS REF ALT VARIANT_LIST 209T-D 459T-D 644T-D + 94T-D 99T1-D 99T2-D 99T3-D 99T4-D 99T5-D ['MT', '1010', 'G', 'A', 'A', 'REF', 'A', 'A', 'REF', 'A', 'A', 'A', ' +A', 'A'] ['MT', '2962', 'C', 'T', 'T', 'REF', 'T', 'T', 'T', 'T', 'T', 'T', 'T' +, 'T'] ...
    I really do not know what is going wrong? If you have any suggestions please let me know. Thanks!

      Hello again corcra,

      Looks like a number of things have changed in your specification. First, the input file headers (but not the data) have lost their square brackets and quotation marks. Second, the criteria for generating the output have changed. From the original post:

      I am trying to write a code which prints out file 1 again but if the sample value is not 'REF', looks up file 2. If the corresponding file 2 value is 'REF' then print the original value appearing in file 1. If the corresponding value in file 1 is not 'REF' then print the value we find in file 2.

      But now you say:

      the same letter at the same position in File 1 and File 2 should output REF, and if REF is found at that position in file 2, just output letter from File 1

      Third, the numbering of input file column headers no longer begins at 1. Will these numbers always increase in value from left to right? Probably safer to assume not, and to formulate a more general solution. In the following, I have simplified the input file formats by removing the square brackets and commas from the data as well as the headers:

      Now some general advice:

      1. In programming, nailing down the specification is half the battle. And by “nailing down” I mean specifying precisely. If you can’t write down exactly what the programme is supposed to do, and how it is supposed to do it, you don’t properly understand what you are doing, which makes it (a) unlikely that you will succeed, and (b) harder to get help. Prepare a table of inputs and expected outputs, then go over all the possible input permutations and ensure that your table specifies the correct outcome for every case.
      2. I hope the above script is useful, but it won’t help you much in the long run if you don’t make an effort to understand what the code is doing, and where and why it has changed to meet the changed requirements. In the future, it will be better if you ask specific questions about the code, after showing that you’ve made a concerted effort to solve your own problem first.

      Hope that helps,

      Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

        Hi Athanasius, Thank you again for your help and advice! I will code more thoughtfully in the future.