我最近“需要”一个zip函数在Perl 5(而我正在考虑大约
How do I calculate relative time?),即一个函数,需要两个列表和“拉链”他们在一起列表,交织元素。
(伪)示例:
@a=(1,2,3); @b=('apple','orange','grape'); zip @a,@b; # (1,'apple',3,'grape');
Haskell has zip in the Prelude和Perl 6 has a zip operator内置,但是你如何在Perl 5中以优雅的方式做呢?
解决方法
假设你有两个列表,它们的长度完全相同,这里是一个由merlyn(Randal Schwartz)最初的解决方案,他将其称为periter:
sub zip2 { my $p = @_ / 2; return @_[ map { $_,$_ + $p } 0 .. $p - 1 ]; }
这里发生的是,对于10个元素的列表,首先,我们找到中间的枢轴点,在这种情况下为5,并将其保存在$ p。然后我们创建一个索引列表到这一点,在这种情况下0 1 2 3 4.接下来我们使用map将每个索引与另一个索引配对与枢轴点相同的距离,因为第一个索引是从开始,给我们(在这种情况下)0 5 1 6 2 7 3 8 4 9.然后我们从@_使用一个切片作为索引列表。这意味着如果将’a’,’b’,’c’,1,2,3传递给zip2,它将返回重新排列为’a’,1,’b’,2,’c’,3 。
这可以写在ysth的单行表达式像这样:
sub zip2 { @_[map { $_,$_ + @_/2 } 0..(@_/2 - 1)] }
是否要使用这两种变体取决于你是否能够看到自己记住它们是如何工作的,但对我来说,这是一个思维扩展器。