Отображение ключей в хеше - если существует, карта
Я пытаюсь сравнить содержимое файла с хэшем хэшей. Для этого я использую 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}