代码之家  ›  专栏  ›  技术社区  ›  Peter Stuifzand

如何反转数组引用并将其存储在Perl中的另一个数组引用中?

  •  2
  • Peter Stuifzand  · 技术社区  · 15 年前

    我有一个例子:

    my $numbers = [ 1, 2, 3, 4, 5, 6 ];
    my $newarray = [ reverse @$numbers ];
    

    此示例包含一些合成代码,以使 $numbers 适合于 reverse 功能。我想删除该代码并执行以下操作:

    my $newarray = reverse $numbers;
    

    我知道这不管用,它会返回:

    )8936f22x0(YARRA
    

    有没有更好的方法在Perl中反转arrayRef 不改变第一行 ?

    更新 :

    my $mails = [ reverse @{$mail_api->GetLogSendMail({ customer_id => $id })} ];
    

    其目的是使上述代码行更好。

    6 回复  |  直到 15 年前
        1
  •  9
  •   Ivan Nevostruev    15 年前

    如果可以使用array而不是arrayref,请尝试以下操作:

    my @newarray = reverse @$numbers;
    

    代码 my $newarray = reverse $numbers 不工作是因为 reverse 被调用 标量 上下文,使其返回一个字符顺序相反的字符串。从 reverse manual :

    在标量上下文中,连接list的元素并返回一个字符串值,其中所有字符的顺序都相反。

    如果在上面某处声明$newarray变量,则可以按以下方式编写:

    ## declare $newarray somewhere else
    @$newarray = reverse @$numbers;
    

    更新

    可能您希望创建自己的函数:

    sub reverse_by_ref {
        return [ reverse @{$_[0]} ];
    }
    
        2
  •  7
  •   Evan Carroll    15 年前

    我认为最根本的问题是 $numbers 作为一个数组引用并尝试作为数组对其进行操作。这可能是个普通的地方,但并不正确。人们这样做是为了保持数组在引用形式上的一致性,但正确的方法是使用本机结构,而不是引用它。以参考形式 scalar , reverse , pop/push/shift/unshift 而所有其他的操作都需要显式的尊重。这对于所有允许引用数组的语言都是通用的——看看C的字符指针与字符数组以及sizeof()运算符之类的东西。实际上,我们在这里所做的是使用Perl极其方便的匿名数组语法,这会对您造成损害。

    这不是一个真正的问题,但有一个小的开销的引用和几乎不可避免的视觉元素的尊重。现在转到/右边/答案。有一个现代的解决方案 autobox . autobox提供类对象语法中包含的所有类型引用。

    use autobox;
    my $arr = [ 1 .. 10 ];
    $arr->reverse;
    

    只是为了跟进,真正的原因 为什么? 我们使用匿名数组语法是为了创建深层结构并避免传递数组(需要将它们推到堆栈上),而不是创建应该是数组作为数组引用的东西。

    • $foo( [1..100] ) $foo( 1..100 )
    • $arr[1] = [1,2,3] @temp = 1,2,3; $arr[1] = \@temp
        3
  •  6
  •   Community CDub    7 年前

    你有几个选择。

    不要把这些都塞进一行:

    my $mails = [ reverse @{$mail_api->GetLogSendMail({ customer_id => $id })} ];
    

    变成:

    my $mails = $mail_api->GetLogSendMail({ customer_id => $id });
    @$mails = reverse @$mails;
    

    如果 GetLogSendMail 愚蠢到返回对不应处理的数组的引用,然后必须稍微修改该引用以创建新数组:

    my $inviolate_mails = $mail_api->GetLogSendMail({ customer_id => $id });
    my $mails;  @$mails = reverse @$inviolate_mails;
    

    要使所有内容保持一行,请使用ivan nevostruev建议的子例程:

    sub reverse_ref \@ {
        return [ reverse @{$_[0]} ];
    }
    
    my $mails = reverse_ref $mail_api->GetLogSendMail({ customer_id => $id });
    

    如果需要在数组引用上加载列表操作,请考虑创建库:

    package ArrayRef::Util;
    # boiler plate skipped.
    
    sub reverse_ref \@ {
        return [ reverse @{$_[0]} ];
    }
    
    sub push_ref \@\@ {
        push @{$_[0]}, @{$_[1]};
    }
    
    # and so on
    

    最后,埃文·卡罗尔的 autobox 建议也有帮助:

    use autobox;
    
    my $mails = [ $mail_api->GetLogSendMail({ customer_id => $id })->reverse ];
    

    Should I use autobox in Perl? 更多关于汽车箱的信息。

        4
  •  2
  •   Michel Gokan Khan    15 年前

    你在找这样的东西吗:

    #!/usr/bin/perl
    
    $myNames = ['Jacob', 'Michael', 'Ethan', 'Andrew'];
    @reversedNames = reverse(@$myNames); 
    
    print @reversedNames;
    

    看一看 this 辅导的。

        5
  •  0
  •   Eric Strom    15 年前

    我不知道你是否控制了原始对象的源,但是如果你控制了,那么添加一个 ->reverse 那个包裹的方法?

    my $mails = $mail_api->GetLogSendMail({ customer_id => $id })->reverse;
    
        6
  •  0
  •   Dan    15 年前

    两个问题:

    1. 你能控制多少东西 $mail_api 是?
    2. 你真的需要 $mails 作为引用而不是实际数组?为什么呢?

    如果1的答案是“some”,2的答案是“no”,则更改 GetLogSendMail 方法返回列表而不是数组引用。然后你的代码变得简单

    my @mails = reverse $mail_api->GetLogSendMail({ customer_id => $id });