Отображение ключей в хеше - если существует, карта

Я пытаюсь сравнить содержимое файла с хэшем хэшей. Для этого я использую map, if а также exists хотя пока неэффективно.

В основном, я хочу знать, существуют ли столбцы от 0 до 2 файла в хэше. Если так, то я хочу выяснить, существует ли столбец 3 в качестве ключа во внутреннем хеше. Мой "старый file.txt" - это файл, разделенный табуляцией, из которого я создаю следующий хеш:

старый файл.txt:

A    s.av    u
B    s.bv    u
C    s.av    u
C    s.cv    m

Hash:

my %oldhash = {
  'A' => {'s.av' => ['u']},
  'B' => {'s.bv' => ['u']},
  'C' => {'s.av' => ['u'], 's.cv' => ['m']},
};

Посмотрите, существуют ли в хэше следующие столбцы, разделенные табуляцией из "new file.txt":

D    Db    Dc    s.av   #cols 0 - 2 do not exist in hash
E    A     Ab    d.ef   #column 1 exists, but column 3 doesn't, so nothing is done
E    A     Ac    s.av   #col 1 and 3 exist, so the new file will have the value of $oldhash{A}{s.av}
B    Bb    B     s.bv   #col0 and 3 exist, so I'll include the value of $oldhash{B}{s.bv}

Обратите внимание, что столбцы 0 и 2 существуют в хэше, но это не важно, поскольку мне нужен только один из столбцов.

Вывод может быть в точности как файл тестирования с добавленным столбцом, который принимает u или же m из другого файла. Пример:

D    Db    Dc    s.av       #inserts empty column
E    A     Ab    d.ef       #inserts empty column
E    A     Ac    s.av   u   #with u inserted
B    Bb    B     s.bv   u   #with u inserted

Это то, где я так далеко, но я получаю exists argument is not a HASH or ARRAY element or a subroutine at myfile.pl line 24:

#!/usr/local/bin/perl
use strict;
use warnings;
use Data::Dumper;

my $dir='D:\\';

open my $oldfile, "<", "$dir\\old file.txt";
open my $newfile, "<", "$dir\\new file.txt";

my (%oldhash);

# creates the hash of hashes
while (my $odata = <$oldfile>){
    chomp $odata;
    my @oline = split /\t/, lc $odata;
    push @{$oldhash{$oline[1]}{$oline[2]}}, $oline[3];
}

# does the comparison between the file and the hash
while (my $newlines = <$newfile>){
    chomp $newlines;
    my @line = split /\t/, $newlines;
    if (exists map {$oldhash{$_}} @line[0..2]) {
        print $oldhash{$_};
    }
}

close $updatedtax;
close $oldtax;

Я ценю всю помощь, которую вы можете оказать мне! заранее спасибо

1 ответ

Решение

exists требует одного массива или хеш-элемента в качестве параметра. Вы передали ему список скалярных значений, происхождение которых было потеряно после того, как они прошли map,

Вы можете написать свой тест как

if ( grep { exists $oldhash{$_} }, @line[0..2] ) { ... }

но я думаю, что есть лучшие способы написать решение.

Я думаю, что это делает то, что вы хотите, но с данными, которые вы дали, выводит просто u дважды. Вы не показали требуемый результат, как я и просил, так ли это?

Я перевернул ключи, которые вы выбрали для себя %oldhash так что дело может быть немедленно отклонено, просто проверив наличие четвертого столбца (s.av и т.д.) в хеше.

Я также добавил use autodie, так как важно проверить, является ли open был успешным, прежде чем вы пошли дальше и использовали данные из дескриптора файла, и это позволяет избежать проверки каждого случая подробно.

Наконец я добавил chdir 'D:\\' так что вам не нужно ставить перед именами файлов путь к каждому open,

Вывод включает в себя последний столбец "комментарий" от new_file.txt это породило это. Я уверен, что вы можете изменить print заявление, чтобы дать вывод, который вы хотите.

use strict;
use warnings;
use autodie;

use Data::Dump;

chdir 'D:\\';

open my $old_fh, '<', 'old_file.txt';

my %old_data;
while (<$old_fh>) {
  chomp;
  my @fields = split /\t/;
  $old_data{$fields[1]}{$fields[0]} = $fields[2];
  print "@fields\n";
}
close $old_fh;

open my $new_fh, '<', 'new_file.txt';

while (<$new_fh>) {

  chomp;
  my @fields = split /\t/;

  my $new = '';
  if (my $list = $old_data{$fields[3]}) {
    my @possible = grep defined, @{$list}{@fields[0,1,2]};
    $new = $possible[0] if @possible;
  }

  print join("\t", @fields[0..3], $new, $fields[4]), "\n";
}

Содержание %old_data после прочтения файла выглядят так

(
  "s.av" => { A => "u", C => "u" },
  "s.bv" => { B => "u" },
  "s.cv" => { C => "m" },
)

выход

D Db  Dc  s.av    #cols 0 - 2 do not exist in hash
E A Ab  d.ef    #column 1 exists, but column 3 doesn't, so nothing is done
E A Ac  s.av  u #col 1 and 3 exist, so the new file will have the value of $oldhash{A}{s.av}
B Bb  B s.bv  u #col0 and 3 exist, so I'll include the value of $oldhash{B}{s.bv}
Другие вопросы по тегам