问题 如何删除与perl中第二个数组中的某个元素相等的数组元素


只是想知道我是否给了两个数组,A和B,如何删除/删除A中也可以在B中找到的那些元素?这样做最有效的方法是什么?

而且,作为一种特殊情况,如果B是后面的结果数组 grep 在A上,怎么做?当然,在这种情况下,我们可以做一个 grep 在否定的条件下。但是在perl中是否存在类似于另一个数组的补充?

谢谢。


13135
2017-09-22 22:51


起源

作为一种特殊情况,如果对两个数组进行排序,则可以执行更有效的差分运算。但这似乎并不像你追求的那样。 - Mike Sokolov
有关: stackoverflow.com/questions/3700037/... - daxim


答案:


任何时候你在想 found in 你可能正在寻找哈希。在这种情况下,您将创建B值的哈希值。然后你会grep A,检查每个元素的哈希值。

my @A = 1..9;
my @B = (2, 4, 6, 8);
my %B = map {$_ => 1} @B;

say join ' ' => grep {not $B{$_}} @A; # 1 3 5 7 9

正如您所看到的,perl通常不会保持任何形式 found in 表格本身, 所以你必须提供一个。上面的代码可以很容易地包含在一个函数中,但为了提高效率,最好是内联。


7
2017-09-23 01:13



mod +1。该 map 本身相当令人印象深刻,但使用 grep 是惊人的。我花了一段时间才意识到它在做什么。我想知道你是什么 grepping 在意识到你没有真正使用之前 grep 匹配线。如果声明 not $B{$_} 是真的(它将适用于所有不在的键 %B), 的价值 $_ 保存在数组中 grep 命令返回。 - David W.
我喜欢这个,但如果我也想要主导订单怎么办? @A 删除中的所有元素后 @B? perl中有什么东西可以 LinkedHashMap在java? - Qiang Li
@Qiang Li,他的代码确实维护了元素的顺序 @A。 (假设main =维护) - ikegami
@Qiang Li,Tie :: IxHash是创建有序关联数组(如LinkedHashMap)的一种方法,但我不知道这与您的问题或此解决方案有什么关系。 - ikegami
@Zaid:在这种情况下不会有任何自动更新。你应该在写评论之前尝试一下。你不像预期的那样了解Perl。 - Hynek -Pichi- Vychodil


看看吧 noneallpartnotall 方法可用 列表:: MoreUtils。您可以使用此模块中提供的方法执行几乎任何设置操作。

有一个很好的教程可用 Perl培训澳大利亚


3
2017-09-22 23:19





如果您要求最有效的方式:

my @A = 1..9;
my @B = (2, 4, 6, 8);

my %x;
@x{@B} = ();
my @AminusB = grep !exists $x{$_}, @A;

但你会注意到我和我之间的区别 埃里克斯特罗姆 仅适用于更大的投入。

您可以找到方便的功能方法:

sub complementer {
  my %x;
  @x{@_} = ();
  return sub { grep !exists $x{$_}, @_ };
}

my $c = complementer(2, 4, 6, 8);

print join(',', $c->(@$_)), "\n" for [1..9], [2..10], ...;

# you can use it directly of course
print join(' ', complementer(qw(a c e g))->('a'..'h')), "\n";

1
2017-09-23 13:17



它不再是了 有效 比其他工作解决方案(根据定义)。也许你的意思 高效? - ikegami
@ikegami你是对的,它的错字。 - Hynek -Pichi- Vychodil


你最好使用哈希,但你也可以使用 智能匹配。偷窃行为 埃里克斯特罗姆的例子,

my @A = 1..9;
my @B = (2, 4, 6, 8);

say join ' ' => grep {not $_ ~~ @B } @A; # 1 3 5 7 9

0
2017-09-23 03:10



这不像Eric Strom那样扩展。他的解是最坏情况Θ(A + B),但你的解是Θ(A * B) - ikegami


再说一次,你可能最好使用哈希,但你也可以使用 Perl6 ::结。再次偷窃 埃里克斯特罗姆的例子,

use Perl6::Junction qw(none);

my @A = 1..9;
my @B = (2, 4, 6, 8);

say join ' ' => grep {none(@B) == $_} @A; # 1 3 5 7 9

0
2017-09-23 12:08





正如已经提到的那样 埃里克斯特罗姆,无论何时你需要搜索特定的东西,如果你有一个哈希,它总是更容易。

Eric有一个更好的解决方案,但可能很难理解。我希望我的内容更容易理解。

# Create a B Hash

my %BHash;
foreach my $element (@B) {
   $BHash{$element} = 1;
}

# Go through @A element by element and delete duplicates

my $index = 0;
foreach my $element (@A) {
   if (exists $BHash{$element}) { 
      splice @A, $index, 1;    #Deletes $A[$index]
      $index = $index + 1;
   }
}

在第一个循环中,我们只是创建一个由元素键入的散列 @B

在第二个循环中,我们遍历每个元素 @A,同时跟踪索引 @A


-1
2017-09-23 03:06



它失败了,因为它修改了它迭代的数组。所有这些额外的复杂性都会降低其可读性。 - ikegami
@ikegami:将数组复制到新数组,然后将其重命名为原始数组会更具可读性吗?这不是我做的方式。我在努力寻求可读性。 - David W.
首先,你应该担心让它成功。 my @C; for my $e (@A) { push @C, $e if !$B{$e}; } @A = @C; 会让它发挥作用,但这是一个非常复杂的方法 @A = grep { !$B{$e} } @A;。 - ikegami