Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Variable not getting updated in apply

Tags:

perl

Quoting from Perldoc for apply in List::AllUtils

Applies BLOCK to each item in LIST and returns a list of the values after BLOCK has been applied. In scalar context, the last element is returned. This function is similar to "map" but will not modify the elements of the input list.

I want to check whether the number is an Armstrong number or not. Since map in scalar context returns the number of elements and apply returns the last element which is final $sum. I used the following

#!/usr/bin/perl

use List::AllUtils qw(apply sum);
use v5.10;
use strict;
use warnings;

say "Enter the input : ";
my $input_number = <STDIN>;
chomp($input_number);
my $sum;
my $out = apply { $sum += $_ ** 3 } split //, $input_number ;
say $out;

I expect $sum to be returned to $out. But I get the last character of $input_number.

Output :

Enter the input : 
153
3

Edit :

I have the solution for Armstrong number. I need to know why the apply doesn't return $sum and returned the last character of $input_number.

like image 420
xtreak Avatar asked Feb 02 '26 18:02

xtreak


1 Answers

You don't need apply or map, just a for loop:

my $input_number = 153;
my $sum = 0;
$sum += $_ ** 3 for split //, $input_number ;

print ($sum == $input_number) ? "Yep, it's an armstrong num\n" : "nope\n";

If you wanted to pull the last element, you could do that like the following:

my $out = (map {$sum += $_ ** 3} split //, $input_number)[-1];

To show what apply is actually does, one can just look at the source:

sub apply (&@) {
    my $action = shift;
    &$action foreach my @values = @_;
    wantarray ? @values : $values[-1];
}

This makes a copy of the original array, and then runs the code block on each element. Note though, that you must actually change the value of $_ or apply will simply return the original element.

I believe apply was intended specifically for the case of applying a regular expression to an array without being destructive to the original array. For example, the following are equivalent:

my @newarray = apply {s/\n//g} @oldarray;
my @newarray = map {my $text = $_; $text =~ s/\n//g; $text} @oldarray;

So ultimately, the only way to get apply to work in the way you expect with your code is to do the following:

my $out = apply { $_ = $sum += $_ ** 3 } split //, $input_number ;
like image 109
Miller Avatar answered Feb 05 '26 09:02

Miller