2013-09-02 2 views
2

Проблема. У меня есть два массива, как показано ниже.удалить конкретный элемент элемента массива из другого массива

my @arr1 = qw(jon won don pon); 
my @arr2 = qw(son kon bon won kon don pon won pon don won); 

мне нужно удалить первый соответствующий элемент @ arr1 от @ arr2 то есть в приведенном выше примере мне нужно удалить выиграл от @ arr2.

В настоящее время моя логика такова, как показано ниже.

#!/usr/bin/perl 
my @arr1 = qw(jon won don pon); 
my @arr2 = qw(son kon bon won kon don pon won pon don won); 
my @remove_indices =(); 
my $remove_element; 
my $first_remove_index; 
OUTER_FOR: for my $i ([email protected]) { 
    $outer_element = $arr2[$i]; 
    foreach my $innr_element (@arr1) { 
     if($innr_element eq $outer_element) { 
      push(@remove_indices, $i); 
      $first_remove_index = $i; 
      $remove_element = $innr_element; 
      last OUTER_FOR; 
     } 
    } 
} 

for my $i ([email protected]) { 
    $outer_element = $arr2[$i]; 
    if($remove_element eq $outer_element) { 
     push(@remove_indices, $i); 
    } 
} 

if (@remove_indices > 0) { 
     map {splice (@arr2, $_, 1)} reverse(@remove_indices); 
            } 

print "@arr2"; 

Но, похоже, это типичная логика стиля C/C++. Я не могу использовать хэш. Есть ли способ perl сделать то же самое?

+1

Turn '@ arr1' в хэш. Затем зациклируйте над '@ arr2', проверяя, находится ли элемент в хеше. – Barmar

+0

проверить ~ ~ заявление –

+0

@Barmar - я не могу использовать хэш из-за моего требования. Я упомянул об этом. – virus

ответ

1

Вот еще один способ (при условии, что вы хотите, чтобы удалить все вхождения первого элемента):

use strict; 
use warnings; 

my @arr1 = qw(jon won don pon); 
my @arr2 = qw(son kon bon won kon don pon won pon don won); 

for my $elem (@arr2){ 
    if(grep { $_ eq $elem } @arr1){ 
     @arr2 = grep { $_ ne $elem } @arr2; 
     last; 
    } 
} 

print "@arr2"; 

Выход:

son kon bon kon don pon pon don 
+0

'first()' (из ['List :: Util'] (http://search.cpan.org/dist/Scalar-List-Utils/)) будет немного более эффективным, чем ваш первый' grep'. – pilcrow

0

Вы можете использовать простой цикл for и выйти из цикла с last, когда найдете совпадение. Используйте grep, чтобы удалить ключевые слова.

use strict; 
use warnings; 

my @arr1 = qw(jon won don pon); 
my @arr2 = qw(son kon bon won kon don pon won pon don won); 
my @out; 
for my $word (@arr1) { 
    my @new = grep !/^\Q$word\E$/, @arr2; 
    if (@new != @arr2) { 
     print "'$word' found\n"; 
     @out = @new; 
     last; 
    } 
} 
print "@out"; 

Обратите внимание, что я использую \Q ...\E отключить возможные регулярных выражений мета-символы. Сравнение != сравнивает размеры массивов друг с другом, и когда различие будет найдено, мы знаем, что наш наш матч.

0

Я уверен, что есть много способов сделать это. Вот один ...

my @arr1 = qw(jon won don pon); 
my @arr2 = qw(son kon bon won kon don pon won pon don won); 

my $s2 = join '|', @arr2; 


my $item; 
foreach $item (@arr1) { 
     last unless $s2 !~ s/$item//g; 
} 
$s2 =~ s/\|\|/\|/g; 
@arr2 = split /\|/, $s2; 

print Dumper(@arr2); 
1

Вирус, из Конечно, вы можете использовать хэш для этой проблемы.

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

use strict; 

my @arr1 = qw(jon won don pon); 
my @arr2 = qw(son kon bon won kon don pon won pon don won); 

my $i; 
my %h; 
for (@arr2) { push @{$h{$_} }, $i++ } 
for my $a (@arr1) { 
    if (exists $h{$a}) { 
     for (@{$h{$a}}) { 
      $arr2[$_] = ''; 
     } 
     last; 
    } 
} 

@arr2 = grep { length } @arr2; 
print "@arr2\n"; 

Мне было любопытно относительная эффективность различных предлагаемых решений и написала тестовую программу, чтобы испытать их. Вы будете рады узнать, что ваша программа хороша, как и при использовании ваших тестовых данных. Но не тогда, когда массивы начинают расти в размерах!

Что следует ниже, я немного злюсь, но знаю, но здесь все равно. Однако, если вы собираетесь выполнять свое приложение за дваллиона раз в день, вы, вероятно, выиграете, выполнив некоторые бенчмаркинга на вашем оборудовании. Так что медведь со мной :)

Здесь приведены относительные времена процессора для каждого из 5 решений в том порядке, в котором они были размещены выше (наиболее экономичным считается «1»). Первый столбец результатов содержит время процессора, используя данные, используемые в вашем примере, и три следующих столбца увеличивают один или оба из двух массивов, префикс их 50 элементами, содержимое которых не найдено в другом.

First array    @arr1  @arr1 @arr1+50 @arr1+50 
Second array    @arr2 @arr2+50 @arr2 @arr2+50 

Your program     1   7   3  45 
Grep approach 1    1   6   3  43 
Grep approach 2    3   9  33  160 
Convert to string   2   4   3   6 
Using hash     2   6   2   7 

Решение хэшей в два раза больше, чем у процессора, при работе на тестовых данных. Но если вы увеличиваете второй массив на 50 элементов, хэш немного лучше, так как ваше процессорное время теперь увеличилось до 7, тогда как хэш-подход прошел от 2 до 6. Но если оба массива больше, ваша программа нуждается в 45 раз больше CPU-time для завершения, чем это необходимо для исходных данных, тогда как для хеш-программы требуется только 3,5 раза (от 2 до 7).

Очевидно, что все они требуют большего времени процессора, поскольку массивы растут по размеру, но не в тех же пропорциях, и их замедление также не является линейным. Возможно, все они могут быть немного изменены, и я думаю, что результаты изменились бы на разных аппаратных платформах, но они должны были бы разумно показать их относительную эффективность. Вот те времена, когда исходные массивы выросли на 100 элементов вместо 50.

First array    @arr1  @arr1 @arr1+100 @arr1+100 
Second array    @arr2 @arr2+100 @arr2 @arr2+100 

Your program     1  12   5  173 
Grep approach 1    1  12   4  162 
Grep approach 2    3  16  68  612 
Convert to string   2   7   5  12 
Using hash     2  11   3  12 

Так что жеребьевка, следует ли предпочесть 4-ый подход (который преобразует тестовый массив в одну строку и затем через него выполняется регулярное выражение, решение программиста perl программиста с умершим в шерсти) и пятое (которое использует хеш). Маргинально, подход «конвертировать в строку» лучше, что-то, что противоречило бы многим программистам. Это также коротко и легко читается.

Нижняя строка ... если вы будете работать с наборами данных, подобными тем, которые указаны в вашем примере, ваш код в порядке (хотя вы должны исправить «(0 .. @ arr2)» в INNER_LOOP: читать »(0 .. $ # arr2) ").

В противном случае используйте 4-й или 5-й в зависимости от вашего вкуса. Я лично пошел бы за тем, который не является моим, программой «конвертировать в строку», если я был на 100% уверен, что символ объединения не может появиться в данных.

Я думаю, что я бы лучше вернуться к делать что-то продуктивное сейчас :)

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