【问题标题】:how does this work: map used with ternary hook operator and ()这是如何工作的:map 与三元钩子运算符和 () 一起使用
【发布时间】:2011-07-05 07:46:45
【问题描述】:

在上一个问题中,seaworthy 询问如何从数组中删除前 5 个元素: How do I remove the first five elements of an array?

在几个建议中,friedo 提出了这个:

my $cnt = 0; @array = map { ++$cnt < 5 ? ( ) : $_ } @array;

我不明白 ( ) 位。请向我解释这是如何工作的,因为我无法理解它?

我知道三元钩子运算符是这样工作的: (如果有的话)? (然后这样做):(否则这样做)

例如:$a=2; print ($a==2 ? 3 : 4) # 这打印:3 因为我们有: ($a==2 ? 3 : 4) 这意味着:(如果 $a 等于 2)? (然后打印 3):(否则打印 4)

所以用frido的代码,首先$cnt增加到1,然后我们有:

$cnt &lt; 5 ? ( ) : $_ 意思是: if $cnt is less than 5 ? then ( ) : otherwise $_

我可以看到 $_ 位是如何工作的,因为我有时会像这样使用地图:

@array = map { $_, "\n" } @array

这会从 @array 复制一个元素,将副本放入 $,然后添加一个 \n 换行符,然后将 $ 中的值复制回 @array(它对所有值执行此操作在@array 中,所以基本上它为@array 中的每个元素添加换行符)

因此:
@array = map { if $cnt is less than 5 then ( ) otherwise $_ } @array

表示类似:
@array = map { if $cnt is less than 5 then ( ) otherwise copy the element back to @array }

很清楚 ( ) 的意思是“摆脱它” 但我只是不确定它是如何工作的。能解释一下吗?

【问题讨论】:

  • 我在friedo 的回答中添加了一条评论,他强迫map 表现得像grep。最好只使用grepmy $count = 0; my @new_array = grep {++$count &gt; 5} @array;。因为你的问题是它是如何工作的,所以我没有发布作为答案。只是告诉您这一点,以便您在可以使用更好的技术时不要使用复杂的技术。注: splice 可能是最好的,因为它正在使用旨在执行此操作的功能。很多时候,Perl 的作者对这些函数进行了优化,这些函数可能比我们使用其他函数自己构建的函数更快/更好。
  • 使用我添加到原始问题的声明 state 另请参阅我的答案

标签: perl


【解决方案1】:

map 中,数组中的每个项目都被传递到代码块(在$_ 中),在那里它可以转换为其他值。换句话说,map 转换了一个列表。

在这种情况下,我们希望丢弃计数 ($cnt) 小于 5 的值。那么当条件为真时,我们如何让 map 块返回“无”?

我们不能说

my $cnt = 0; @array = map { ++$cnt < 5 ? undef : $_ } @array;

因为我们最终会得到一个看起来像这样的数组

( undef, undef, undef, undef, undef, 6, 7, 8 ... )

这不是我们想要的。

但是返回( ) 反而返回一个空列表。考虑push @foo, ( );@bar = ( 1, 2, 3, ( ), 4, 5, 6 ); 在每种情况下,空括号集是零项列表,对相关数组没有任何影响。

空列表在需要返回列表项或根本不返回任何内容的三元组中很有用。在表达式上强制列表上下文以获取计数也很有用:

my $count = ( ) = $str =~ /\d/g;

在这里,我们通过将正则表达式分配给一个空列表来将正则表达式放入列表上下文中,从而为我们提供字符串中的位数。然后我们将该空列表分配给$count

map 中使用列表的另一个常见示例是将某些内容转换为哈希。例如,

my %unique = map { $_ => 1 } @duplicates;

这里@duplicates 中的每一项都被转换成一个类似于( 'foo' =&gt; 1 ) 的两元素列表,尽管它不那么明显,因为不涉及括号。然后,所有包含两项的列表被构建成一个由交替的键和值组成的大列表,这些键和值构成了散列。假设您想制作此哈希但排除某些项目。在这种情况下,我们要么需要返回一个键/值,要么什么都没有。所以这是使用空列表的好机会:

my %filtered_unique = map { some_test( $_ ) ? ( ) : ( $_ => 1 ) } @duplicates;

【讨论】:

  • 我看到 undef 而不是 () 会增加数组中的元素数量。谢谢friedo,我从你的回答中学到了很多。
【解决方案2】:

我知道我在这里玩得有点晚了,但为什么不做一些简单的事情呢?

我的@truncated = @array[5 .. $#array]

【讨论】:

  • splice 怎么样?
【解决方案3】:

显然,您可以返回一个列表而不是一个元素,并且 map 通过连接这些列表和元素来构造结果。 () 在这种情况下只是一个空列表。如需更多信息,请复制粘贴示例,并将() 替换为(1, 2, 3)

【讨论】:

    猜你喜欢
    • 2012-11-11
    • 2018-08-31
    • 2010-10-02
    • 2023-01-09
    • 1970-01-01
    • 2015-01-11
    • 1970-01-01
    • 2023-03-12
    • 1970-01-01
    相关资源
    最近更新 更多