2014-09-26 3 views
1

Я пытаюсь сопоставить слово отсутствия данных с данными с помощью элементов массива. Мой кодКак совместить отсутствие элементов массива в perl?

use warnings; 
use strict; 
my @ar = qw(one two three four five six seven eight nine ten); 
my @data = <DATA>; 
print "Absence word in the data\n"; 
foreach my $mat(@ar){ 
    my $nonmatch; 
    foreach my $dat (@data){ 
     $nonmatch = grep{m/(?!$mat)/} $dat; 
    } 
    print "$nonmatch\n"; 
} 
__DATA__ 
eight two four one two three four seven eight ten one two seven 

Сначала отсылаем значение элемента массива на элемент массива данных отсутствует в данных, которые только напечатано.

Я ожидал, что выход:

Absence word in the data 
five 
six 
nine 

Как я могу это сделать

+2

Было бы использовать хэш для слов в '@ data', поэтому вы можете просто проверить, существует ли' $ mat' в хэше или нет. –

ответ

2

Использование видели стиль хэш, как моделируется в perlfaq4 - How can I tell whether a certain element is contained in a list or array?

use warnings; 
use strict; 

my %seen = map { $_ => 1 } map { split ' ' } <DATA>; 

my @ar = qw(one two three four five six seven eight nine ten); 

print "Absence word in the data\n"; 
print "$_\n" for grep { !$seen{$_} } @ar; 

__DATA__ 
eight two four one two three four seven eight ten one two seven 

Выходы:

Absence word in the data 
five 
six 
nine 
+1

Вам нужно «chomp' your' '? Или, раскол удалит NL на конце? –

+0

Не нужно 'chomp'. 'split' или' split '' 'являются особыми случаями, которые обрабатываются как' split/\ s +/'с дополнительной функцией, которую удаляет любой предыдущий интервал. Вероятно, после раскола может существовать конечный '' '', но только если мы использовали отрицательный предел. – Miller

1

Вы можете использовать хэш-фрагмент @seen{@r} хранить все видели слова из @r в %seen хэш, и проверить позже эти хэш-ключи против @ar массив,

use warnings; 
use strict; 

my @ar = qw(one two three four five six seven eight nine ten); 
my %seen; 
while (my $mat = <DATA>) { 
    my @r = split (' ', $mat); 
    @seen{@r} =(); 
} 
print "Absence word in the data\n"; 
print "$_\n" for grep { not exists $seen{$_} } @ar; 

__DATA__ 
eight two four one two three four seven eight ten one two seven 

выход

Absence word in the data 
five 
six 
nine 
+0

Прокомментируйте это при голосовании. –

+0

Спасибо @mpapec Это работает Пожалуйста, объясните свой код. Я не понимаю, как объявить hasesh? – mkHun

1

Это звучит как вопрос, который я имел в одной точке, и код, который я придумал был следующий код, который я создал на основе информации на этой странице:

https://www.safaribooksonline.com/library/view/perl-cookbook/1565922433/ch04s08.html

# assume @A and @B are already loaded 
%seen =();      # lookup table to test membership of B 
@aonly =();      # answer 

# build lookup table 
foreach $item (@B) { $seen{$item} = 1 } 

# find only elements in @A and not in @B 
foreach $item (@A) { 
    unless ($seen{$item}) { 
     # it's not in %seen, so add to @aonly 
     push(@aonly, $item); 
    } 
} 
1

Создайте хэш, содержащий все слова из __DATA__ как ключи (можно сделать в одной строке с использованием хэш-фрагмента), затем отфильтруйте слова не в хеше (также можно сделать в одной строке с помощью grep).

use warnings; 
use strict; 
my @ar = qw(one two three four five six seven eight nine ten); 

my $data = join '', (<DATA>); 
my @data_words = split ' ', $data; # get a list of words 

my %data; 
@data{@data_words} = @data_words; # fill a hash with the words from __DATA__ 

my @missing = grep { !exists $data{$_}; } @ar; # filter words 

print "Absence word in the data: @missing\n"; 

__DATA__ 
eight two four one two three four seven eight ten one two seven 
0

Это решение начинается с списком вещей, которые вы ищете, и капли, что вы видите на этом пути, а затем печатает то, что осталось.

Вы можете оптимизировать это для больших данных, проверив нижнюю часть цикла while, если в %unseen есть еще какие-либо ключи. Я добавил еще одну строку и слово «шестнадцать» в ваши тестовые данные, чтобы убедиться, что она работает с несколькими строками и что мы не получили ложного позитива для «шестерки».

use warnings; 
use strict; 

my @to_match = qw/ one two three four five six seven eight nine ten /; 
my %unseen; 
$unseen{$_} = 1 for @to_match; 
while (my $line = <DATA>) { 
    foreach my $match_this (@to_match) { 
     delete $unseen{$match_this} if $line =~/\b$match_this\b/; 
    } 
} 
print "Words absent from the data:\n". join "\n", keys %unseen; 
print "\n"; 
__DATA__ 
eight two four one two three four seven eight ten one two seven 
sixteen 
+0

Просьба прокомментировать при downvoting - это решение другого подхода с полезной возможной оптимизацией - я не тестировал широко, но я считаю, что он работает. – msouth

1

две вещи:

Всегда chomp, что вы читали в этом включает __DATA__.:

my @data = <DATA>; # The NL is in each element 
chomp @data;   # Now it isn't! 

Если вы не chomp, вы будете проверять, соответствует ли oneone\n. Кроме того, поскольку вы помещаете весь __DATA__ на одну строку, он будет считаться одной строкой ввода. Вам нужно будет использовать split, чтобы разделить его на массив.

Вторая вещь: Обычно, когда вы спрашиваете , это в этом ли?t типа вопросов, вы должны сразу подумать о хешах. Хэш может быстро использоваться для поиска элемента. В этом случае, вы бы сделать хэш данных, а затем проверить, если каждый элемент в списке в этом хэша:

#! /usr/bin/env perl 
# 

use strict; 
use warnings; 
use feature qw(say); 

my @list = qw(one two three four five six seven eight nine ten); 
my @data = <DATA>; 
chomp @data;  # Don't forget! 

# 
# Translate your input as a hash 
# 

my %data_hash; 
for my $element (@data) { 
    $data_hash{$element} = 1; 
} 

for my $element (@list) { 
    if (not exists $data_hash{$element}) { 
     say "$element isn't in the list"; 
    } 
} 
__DATA__ 
eight 
two 
four 
one 
two 
three 
four 
seven 
eight 
ten 
one 
two 
seven 

Обратите внимание, что команда map дает вам более короткий способ написания этого цикла:

# 
# Translate your input as a hash 
# 

my %data_hash; 
for my $element (@data) { 
    $data_hash{$element} = 1; 
} 

Теперь может быть сокращен до одной строки:

# 
# Translate your input as a hash 
# 

my %data_hash = map { $_ => 1 } @data; 

Это обычный способ превратить массив в хэш, поэтому большинство разработчиков просто использовать его.

Смежные вопросы