【问题标题】:Filtering elements of an array with elements of another array in Perl 6在Perl 6中用另一个数组的元素过滤一个数组的元素
【发布时间】:2017-10-25 13:32:23
【问题描述】:

我想过滤以@search 元素开头的@array 元素:

my @array = "aaaaa" .. "fffff";
my @search = "aaaa" .. "cccc";
.put for @array .grep: /^ @search /;

问题是它需要 19 秒。所以,我把'precompile'regex换成grep,整个程序是这样的:

my @array = "aaaaa" .. "fffff";
my @search = "aaaa" .. "cccc";

my $search = "/@search.join('|')/".EVAL;

.put for @array .grep: * ~~ /^ <$search> /;

现在需要 0.444 秒。

问题:有没有内置的 Perl 6 方法来做这些事情?类似于将junction 插入regex...

【问题讨论】:

  • 您所说的“为之工作”是什么意思?这么长时间后它会崩溃吗?
  • .put for @array .grep: @search.any;
  • @BradGilbert 输出将是错误的。例如。 faaaa 将被过滤,但不应该。过滤后的元素应以来自@search 的字符串开始。 (即我正在寻找regexes 的解决方案)
  • @BradGilbert:你必须用 grep 搜索 *.starts-with(@search.any)
  • @Christoph 哦,是的,这解决了这个特殊情况,这是我的错。 :) 虽然我正在寻找更通用的东西来将字符串合并到regex

标签: raku


【解决方案1】:
my @array = "aaaaa" .. "fffff";
my @search = "aaaa" .. "cccc";
my $join = @search.join('|');
my $rx = rx{ ^ <{$join}> };

@array.grep( * ~~ $rx ).map( *.put )

您需要单独创建连接字符串,它将评估每个匹配项的数组连接。但是基本上不使用 EVAL 就可以为您提供所需的东西。

【讨论】:

  • 谢谢!如果我没记错的话,EVAL 的功能是由内部的{} 执行的?
  • &lt;{ }&gt; 在正则表达式中评估内部块并将字符串结果放入正则表达式。这意味着您不要使用具有潜在危险的EVAL 方法。
【解决方案2】:

您可以尝试通过组装正则表达式来加快速度。

我不确定如何使用纯 Perl 6 来做到这一点,但 Regexp::Assemble 是一个 Perl 5 模块,它可以为 Perl 5 做到这一点em> 正则表达式。您可以在 Perl 6 代码中使用 Perl 5 模块,方法是将 :from&lt;Perl5&gt;(前面不带空格)附加到 use 语句,然后访问其导出的符号(类、对象、例程等),就好像它是一个 Perl 6 模块:

use v6;

use Regexp::Assemble:from<Perl5>;

my @array = "aaaaa" .. "fffff";
my @search = "aaaa" .. "cccc";
my $ra = Regexp::Assemble.new;
$ra.add( @search );
$ra.anchor_string_begin(1);
.put for @array.grep({so($ra.match( $_ ))});

【讨论】:

  • 谢谢,一个有趣的解决方案。我怎样才能安装这个 Perl 5 模块?然而我想知道,是否有一种纯粹的 v6 方式来做到这一点......
  • @EugeneBarsky 我使用perlbrew。按照Inline::Perl5GitHub page 的说明安装可重定位的perl。然后为perlbrew 安装cpanm,使用perlbrew install-cpanm,另请参阅metacpan.org 上的文档。然后安装 Perl 5 模块 Regexp::Assemble 使用 cpanm Regexp::Assemble.. 希望这会有所帮助!
【解决方案3】:

对于这种搜索,您可以轻松使用index

say (@array X @search).grep( { defined($^a[0].index($^a[1])) } )
    .grep( { $^a[0].index($^a[1]) == 0 } );

这会创建一个 C 列表,并在第一个元素中查找该对的第二个元素;它只返回出现在第一个位置的列表。 defined 是必需的,因为如果找不到它,它将返回 Nil。它并不比您上面的替代方案快,但它在同一个球场内,系统时间为 0.03 和 ~ 0.30 秒

【讨论】:

  • 在这种情况下使用.starts-with() 不是更容易吗?我仍然不明白为什么我们不能只使用第二个.grep——Nil == 0 会给出False,所以这些元素将被过滤掉。
  • Nil 将发出警告。但是starts-with 是有道理的。
猜你喜欢
  • 2013-02-26
  • 1970-01-01
  • 1970-01-01
  • 2019-01-03
  • 1970-01-01
  • 2018-03-07
  • 1970-01-01
  • 2016-04-26
  • 2019-01-18
相关资源
最近更新 更多