【问题标题】:How do I multiply each member of array by a scalar in perl?如何将数组的每个成员乘以 perl 中的标量?
【发布时间】:2011-08-05 23:28:21
【问题描述】:

这里是代码...

use strict;
use warnings;

my @array= (1,2,3,4,5);
my $scalar= 5;

@array= $scalar*@array;

print @array;

需要可以用很少的代码执行类似功能的东西。谢谢!

【问题讨论】:

  • 要操作更大的数组,您可能需要查看 PDL pdl.perl.org

标签: arrays perl scalar


【解决方案1】:

使用 foreach。

foreach my $x (@array) { $x = $x * $scalar; }

【讨论】:

  • +1。对于大型列表,foreach 方法比 map 更快。
  • @Alex - 在数组上下文中这可能是正确的,但在无效上下文中是无休止的辩论主题(就像我的第二个版本)。它显然是特定于平台和版本的。此外,map 可以(原则上)由系统并行化,而 foreach 通常不能,因此至少有可能 map 可以比 foreach 执行得更快。
  • @Ted Hopp,map 的并行处理可能会进入 Perl 6,但它可能永远不会进入 Perl 5。太多的代码依赖于有序迭代地图声明。 Perl 5 对perl 的副作用很严重,无法识别哪些地图主体完全没有副作用。
  • map 的速度取决于 perl 版本。较新版本的 Perl 可以识别何时在 void 上下文中调用 map,并且不会存储 map 的结果,然后在最后丢弃结果,旧版 Perl 就是这样做的。
  • @SoloBold - 只需谷歌“perl map vs foreach”即可获得很多好的讨论。 perlmonks.org 上的那些往往消息灵通且具体。
【解决方案2】:

这个怎么样:

foreach(@array)
{ $_ *= $scalar }

如您所见,您可以在遍历数组时就地修改它。

【讨论】:

  • 如果您要依赖隐式 $_,您不妨为 @array 执行 $_ *= $scalar
【解决方案3】:

你可以试试这个:

@array = map { $_ * $scalar } @array;

或更简单地说:

map { $_ *= $scalar } @array;

【讨论】:

  • 你不应该在地图块中修改 $_
  • @MkV - 为什么不呢?来自perldoc page for map:“请注意,$_ 是列表值的别名,因此可用于修改 LIST 的元素。”这是转换数组的所有元素的常用习语。
  • “虽然这很有用且受支持,但如果 LIST 的元素不是变量,则可能会导致奇怪的结果。在大多数情况下,为此目的使用常规 foreach 循环会更清晰。”
  • @MkV,但列表的元素是变量。也就是说,我自己会使用$_ *= $scalar for @array;
  • @ikegami - 我可能也会同意你的建议,毕竟说了又做了。不是出于性能原因,而是因为它让我觉得它比其他任何东西都更具可读性。 :)
【解决方案4】:

此评论适用于 SoloBold。

这是map 方法的测试:

#!/usr/bin/perl                                                                                                                                                                                                          

use strict;
use warnings;
use Benchmark;

my @array = ();
push(@array, (1) x 1000000);
my $scalar = 5;

my $startTime = new Benchmark();

@array = map { $_ * $scalar } @array;

my $stopTime = new Benchmark();

print STDOUT "runtime: ".timestr(timediff($stopTime, $startTime), 'all')." sec\n";

这是foreach 方法的测试:

#!/usr/bin/perl                                                                                                                                                                                                          

use strict;
use warnings;
use Benchmark;

my @array = ();
push(@array, (1) x 1000000);
my $scalar = 5;

my $startTime = new Benchmark();

foreach my $x (@array) { $x = $x * $scalar; }

my $stopTime = new Benchmark();

print STDOUT "runtime: ".timestr(timediff($stopTime, $startTime), 'all')." sec\n";

这是我正在运行的系统:

bash-3.2$ perl --version
This is perl, v5.8.8 built for darwin-2level
...
bash-3.2$ uname -a
Darwin Sounder.local 10.7.0 Darwin Kernel Version 10.7.0: Sat Jan 29 15:17:16 PST 2011; root:xnu-1504.9.37~1/RELEASE_I386 i386

以下是一项测试的结果:

bash-3.2$ ./test.map.pl
runtime:  4 wallclock secs ( 0.41 usr  0.70 sys +  0.00 cusr  0.00 csys =  1.11 CPU) sec
bash-3.2$ ./test.foreach.pl
runtime:  0 wallclock secs ( 0.13 usr  0.00 sys +  0.00 cusr  0.00 csys =  0.13 CPU) sec

这些时间在同一台机器上是相当可重现的,结果在双核 Linux 机器上有些可重复:

[areynolds@fiddlehead ~]$ perl --version
This is perl, v5.8.8 built for x86_64-linux-thread-multi
...
[areynolds@fiddlehead ~]$ uname -a
Linux fiddlehead.example.com 2.6.18-194.17.1.el5 #1 SMP Mon Sep 20 07:12:06 EDT 2010 x86_64 GNU/Linux
[areynolds@fiddlehead ~]$ ./test.map.pl
runtime:  0 wallclock secs ( 0.28 usr  0.05 sys +  0.00 cusr  0.00 csys =  0.33 CPU) sec
[areynolds@fiddlehead ~]$ ./test.foreach.pl
runtime:  0 wallclock secs ( 0.09 usr  0.00 sys +  0.00 cusr  0.00 csys =  0.09 CPU) sec

mapforeach 相比,OS X 机器上的性能比要慢 8.53 倍。在 Linux 机器上,同样慢 3.67 倍。

我的 Linux 机器是双核的,并且比我的单核 OS X 笔记本电脑的内核速度稍快。

编辑

我在我的 OS X 机器上将 Perl 从 v5.8.8 更新到 v5.12.3,并获得了相当大的速度提升,但 map 的性能仍然比 foreach 差:

sounder:~ alexreynolds$ perl --version
This is perl 5, version 12, subversion 3 (v5.12.3) built for darwin-multi-2level
...
sounder:~ alexreynolds$ ./test.map.pl
runtime:  0 wallclock secs ( 0.45 usr  0.08 sys +  0.00 cusr  0.00 csys =  0.53 CPU) sec
sounder:~ alexreynolds$ ./test.foreach.pl
runtime:  1 wallclock secs ( 0.18 usr  0.00 sys +  0.00 cusr  0.00 csys =  0.18 CPU) sec

这从 8.53 倍下降到 2.94 倍。相当显着的改进。

Linux 机器在将其 Perl 安装升级到 v5.12.2 时表现稍

[areynolds@basquiat bin]$ perl --version    
This is perl 5, version 12, subversion 2 (v5.12.2) built for x86_64-linux-thread-multi
...
[areynolds@basquiat bin]$ /home/areynolds/test.map.pl
runtime:  1 wallclock secs ( 0.29 usr  0.07 sys +  0.00 cusr  0.00 csys =  0.36 CPU) sec
[areynolds@basquiat bin]$ /home/areynolds/test.foreach.pl
runtime:  0 wallclock secs ( 0.08 usr  0.00 sys +  0.00 cusr  0.00 csys =  0.08 CPU) sec

这从 3.67 倍恶化到 4.5 倍 - 不太好!升级可能并不总是花钱,只是为了它。

【讨论】:

    【解决方案5】:

    我不知道您的需求范围。如果您正在进行数值数据操作,Perl 数据语言 (PDL) 会获取一组数值数据,从中创建一个“piddle”对象并重载数学运算以“矢量化”它们的运算。这是一个非常有效的数值处理系统。无论如何,这是一个例子:

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    use PDL;
    
    my $pdl_array = pdl([1,1,2,3,5,8]);
    print 2*$pdl_array;
    
    __END__
    gives:
    [2 2 4 6 10 16]
    

    【讨论】:

    • 有趣。我有大约 1000 个元素长的数据集,我必须反复对它们做一些事情。我想知道 PDL 是否比 perl 快很多?
    • 是数字。我会试一试。
    【解决方案6】:

    我觉得拉里不允许

    $标量运算符(列表)

    (列表)运算符 $标量

    当然 map 或 loops 可以做到这一点,但语法比上面的要干净得多。

    也(列表)运算符(列表)

    如果 2 的长度相等,也有意义。

    惊讶的拉里不允许这些,只是说..我想在这种情况下有 (n-1) 种方法可以做到这一点。

    喜欢

    我的 @a = 'n' 。 (1..5); 我的@a = 2 * (1..5);

    甚至 我的@a = 2 * @b;

    【讨论】:

      猜你喜欢
      • 2018-12-09
      • 1970-01-01
      • 2013-07-17
      • 2013-04-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-15
      • 2021-01-11
      相关资源
      最近更新 更多