【问题标题】:Why does this map return a single number?为什么这张地图返回一个数字?
【发布时间】:2009-10-19 15:56:36
【问题描述】:

我正在尝试减少我正在使用的代码行数,但最终遇到了一个相当简单的问题(尽管这让我很困惑,因为我刚刚开始思考参考资料)

我正在尝试以特定顺序连接多个值。我的代码如下所示。

my $separator = ":";
my @vals = qw(name last-name first-name phone);
my $return_name;
$return_name = map { 
    $return_name = $return_name . $query->param($_) . $separator 
} @vals;

我得到的是“4”,而不是全部连接成一个字符串。

我想要实现的是...的更短版本

$return_name = $query->param('name') . 
    $separator . $query->param('last-name') . 
    $separator . $query->param('first_name') . 
    $separator . $query->param('phone');

(我实际上是在尝试将大约 25 个 $query->params 串在一起。为简洁起见,我只给出了四个)

【问题讨论】:

    标签: perl arrays string-concatenation


    【解决方案1】:

    您的部分问题是对 map 的工作方式感到困惑。

    map 接受参数列表,对列表的元素执行操作并根据结果创建一个新列表。在标量上下文中,它返回新列表中的成员数。

    在大多数情况下,您不想在 map 操作中进行分配。

    # no assignment needed to set @foo
    my @foo = map $_+2, 1,2,3; 
    # @foo = (3,4,5);
    

    赋值有意义的一个地方是,如果您需要使用通常会更改 $_ 值的操作,但您需要保持映射的参数不变。

    这个解释不是很清楚。看看这些例子,它们应该有助于澄清我在说什么。第一个显示你映射可以改变它处理的值:

    my @foo = qw( fee fie foe fum );
    my @bar = map { s/e/-/g } @foo;
    # @foo = ( 'f--', 'fi-', 'fo-', 'fum' ); 
    # @bar = ( 2, 1, 1, '' );
    

    为了避免改变@foo,你可以这样做:

    my @foo = qw( fee fie foe fum );
    my @bar = map { my $val = $_; $val =~ s/e/-/g } @foo;
    # @foo = ( 'fee', 'fie', 'foe', 'fum' ); 
    # @bar = ( 'f--', 'fi-', 'fo-', 'fum' ); 
    

    或者你可以这样做:

    使用 List::MoreUtils qw( apply );

    my @foo = qw( fee fie foe fum );
    my @bar = apply { s/e/-/g } @foo;
    # @foo = ( 'fee', 'fie', 'foe', 'fum' ); 
    # @bar = ( 'f--', 'fi-', 'fo-', 'fum' );
    

    最基本的map 就像for 循环的特殊形式一样工作。这两段代码产生完全相同的结果:

    my @foo = map {$_ * 2} 1..5;
    
    my @bar;
    for (1..5) {
         my $val = $_ * 2;
         push @bar, $val;
    }
    

    我希望这对您了解如何思考map 有所帮助。一旦您学会了使用它(以及相关的结构,如 grepapply),您将能够简洁地表达使用普通循环代码构建时可能非常冗长的想法。

    【讨论】:

    • daotoad,这是我能得到的最佳答案。我的意思是每个人都非常乐于助人,但您的回答确实帮助我最大地理解它。
    【解决方案2】:
    $return_name = map { $return_name = $return_name . $query->param($_) . $separator } @vals;
    

    这是一个标量赋值,它给出了映射操作标量上下文。 map 在标量上下文中返回将产生的元素的计数。

    虽然特定的代码行要求使用 join(),但如果您有函数式编程背景,您可能更适合使用 reduce:

    use List::Util 'reduce';
    $return_name = reduce { $a . $query->param($b) . $separator } "", @vals;
    

    【讨论】:

      【解决方案3】:

      map 返回一个列表,而不是一个字符串。试试这个:

      $return_name = join $separator, map { $query->param($_) } @vals;
      

      或者如果你真的想减少行数,试试这个:

      my $return_name = join ':', 
          map { $query->param($_) } 
          qw(name last-name first-name phone);
      

      (单行版本的灵感来自 dsm 的回答。)

      【讨论】:

      • 我相信上面的 dsm 也可以。 jbourque 它就像一个冠军!谢谢!
      【解决方案4】:

      试试这个:

      join $separator, 
           map { $query->param($_) } 
           ("name", "last-name", "first-name", "phone");
      

      要回答您得到“4”的原因,这是因为您将结果数组的基数分配给一个标量。

      【讨论】:

        【解决方案5】:

        除了您收到的所有好的答案之外,请注意

        $return_name = $return_name . $query->param($_) . $separator;
        

        可以写成

        $return_name .= $query->param($_) . $separator;
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-03-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多