У меня есть массив, как показано ниже:
my @arr = qw (ram sam ham dam yam fam lam cam)
Я хочу удалить sam
, yam
и lam
из приведенного выше массива, используя splice
.
Для этого я использую код ниже:
# first getting the index of sam
(my $ind ) = grep {$arr[$_] eq 'sam'} 0 .. $#arr;
splice(@arr, $ind, 1);
Мой вопрос: поскольку элементы массива изменили свое положение, мне нужно снова получить индекс yam
и lam
и выполнить соединение массива.
Есть ли другой способ, чтобы за один раз удалить случайные элементы из массива с помощью сращивания. Я могу получить индекс всех из них одновременно и удалить их из массива, но эти позиции будут содержать значение undef, чего я не хочу.
без особой причины, точно так же, как сращивание не оставляет undef в удаленной позиции.
my %h = map {$_=>1} qw(sam yam lam); @arr = grep { !defined $h{$_} } @arr;
?
Что насчет этих элементов делает их «случайными»? На этот вопрос вы получите ответы только на удаление предопределенных элементов, а не случайных элементов.
Я предполагаю, что вы читаете эти данные из файла или чего-то подобного, а не вводите данные, которые через 3 секунды хотите удалить. В этом случае удаление, возможно, следует производить при чтении данных и другим способом.
@TLP они случайны в том смысле, что они не являются последовательными числами, такими как 2,3,4 или 1,2 3 и т. д., поэтому я могу использовать сращивание. Индексы такие, как 2,4,7. Да, элементы предопределены, но их позиции в массиве случайны.
@A.G.Progm.Enthusiast Ах, вы имеете в виду случайные индексы, а не случайные элементы. Я бы выбрал выбор, когда вы собираете элементы массива, а не потом.
Если вы знаете значения элементов, которые нужно удалить (sam
и т. д. в данном случае), а не индексы, можете сделать
my $re = join '|', map { q(^) . quotemeta . q(\z) } qw(sam yam lam);
my @filtered_ary = grep { not /$re/ } @ary;
или, действительно
my $re = join '|', map { quotemeta } qw(sam yam lam);
$re = qr/^(?:$re)\z/;
my @filtered_ary = grep { not /$re/ } @ary;
Также можно перезаписать массив
@ary = grep { ... } @ary
См. quotemeta , которая экранирует «все символы ASCII, не являющиеся словесными», чтобы символы со специальным значением в регулярном выражении можно было использовать в качестве буквальных символов, и qr, создавая регулярное выражение. Использование qr
в большинстве случаев не обязательно, но я считаю это хорошей практикой.
Нет необходимости сначала найти индекс, чтобы использовать splice
(который вам придется использовать повторно для всех несмежных индексов).
Или, как в jhnc
комментарии
my %remove = map { $_ => 1 } qw(sam yam lam);
@ary = grep { not $remove{$_} } @ary;
Это быстрее, чем решение, приведенное выше, поскольку оно выполняет только поиск вместо регулярного выражения, а их накладные расходы довольно схожи.
Возможно, это не лучший способ сделать это, но вы можете удалить их без перерасчета индексов, если сначала удалите самый высокий индекс, а затем вернетесь к самому низкому индексу. Таким образом, ни один элемент, который вы хотите удалить, не изменит свое положение. Для этого вам следует начать со всех уже известных индексов, а затем выполнить отдельный шаг по их удалению.
Это точное решение моего требования.
@A.G.Progm.Enthusiast Это не так. Он имеет в виду, что если вам нужно удалить индексные номера 2, 3 и 7, вы удаляете их в порядке 7,3,2. Таким образом, удаление индекса не повлияет на другие индексы.
@TLP правильно, но предложенный алгоритм (от самого высокого индекса до самого низкого) справляется со своей задачей.
Вы действительно настаиваете на использовании
splice
? Есть какие-то особые причины для этого?