仅在密钥存在时才使用Perl中的map进行映射

时间:2014-10-16 11:36:36

标签: perl map perl-data-structures

我有一个像这样定义的数据结构:

my @columns = (
  {
    db => 'location',
    dt => 'location',
    search => 'location',
  },
  {
    db => 'name',
    dt => 'name',
    search => 'name',
  },
  {
    db => 'iqs',
    dt => 'iqs',
  },
);

我正在映射搜索的值,如下所示:

@where = map +{ $_->{search} => { like => "\%$global_search\%" } }, @columns;

如果密钥搜索不存在,我最终得到的数据结构有很多:

{
    '' => {
        'like' => '%pas%'
    }
},

这完全搞砸了我想要做的事情。所以,我想知道,因为地图在技术上不是一个循环,当关键搜索不存在时如何跳过?

编辑:

下面有人询问地图与循环之间的性能差异,这激起了我的好奇心,所以我决定自己测试一下。结果如下:

守则

#!/usr/bin/env perl
use strict;
use warnings;
use Benchmark qw/cmpthese timethese/;

my $global_search = 'test';


my @columns;
for ( my $i = 0; $i <= 100000; $i++ ) {
    my $hash = {
        db => "test$i",
        dt => "test$i",
        search => "test$i"
    };
    push @columns, $hash;
}

timethese(-30, {
      mapBuild => sub {
        my @where = map {
          exists ($_->{search})
            ? +{ $_->{search} => { like => "\%$global_search\%" } }
            : ()
        } @columns;
      },
      forBuild => sub {
        my @where;
        foreach (@columns) {
          if (exists $_->{search}) {
            push @where, +{ $_->{search} => { like => "\%$global_search\%" } } ;
          }
        }
      },
});

cmpthese(-30, {
      mapBuild => sub {
        my @where = map {
          exists ($_->{search})
            ? +{ $_->{search} => { like => "\%$global_search\%" } }
            : ()
        } @columns;
      },
      forBuild => sub {
        my @where;
        foreach (@columns) {
          if (exists $_->{search}) {
            push @where, +{ $_->{search} => { like => "\%$global_search\%" } } ;
          }
        }
      },
});

结果

  

基准测试:运行forBuild,mapBuild至少30秒CPU秒...
  forBuild:32个wallclock secs(31.66 usr + 0.00 sys = 31.66 CPU)@   980.35 / s(n = 31038)mapBuild:31个wallclock secs(31.58 usr + 0.00 sys = 31.58 CPU)@ 994.21 / s(n = 31397)             Rate forBuild mapBuild forBuild 978 / s - -2%mapBuild 993 / s 2% -

3 个答案:

答案 0 :(得分:4)

传递给map的块在列表上下文中被调用,因此它可以返回一个空列表:

@where = map {
   exists ($_->{search})
      ? +{ $_->{search} => { like => "\%$global_search\%" } }
      : ()
} @columns;

或者你可以先grep

@where =
   map +{ $_->{search} => { like => "\%$global_search\%" } },
   grep exists($_->{search}),
   @columns;

答案 1 :(得分:1)

@where = map {
    $_->{search} => { like => "\%$global_search\%" }
} grep {
    defined $_->{search}
} @columns;

答案 2 :(得分:1)

总是可以尝试将其变成更像英语的循环。

my @where;

for (@columns) {
    if ( exists $_->{search} ) {
        push @where, +{ $_->{search} => { like => "\%$global_search\%" } };
    }
}

是否有人知道我刚写完的内容是否会造成巨大的性能损失,或者它与地图的速度大致相同?