необходимо дважды использовать pop-функцию, чтобы удалить последний элемент из массива (perl)

#perl

#perl

Вопрос:

Я только начал изучать Perl и присоединился к Euler project, чтобы попрактиковаться в кодировании. Это первое упражнение, которое я выполнил. Задача заключалась в следующем: «Если мы перечислим все натуральные числа ниже 10, кратные 3 или 5, мы получим 3, 5, 6 и 9. Сумма этих кратных равна 23. Найдите сумму всех чисел, кратных 3 или 5, меньше 1000.» Мое решение:

 use strict;
use warnings;

my @numbers = (1..1000);
my $counter = 0;
my @all_array = ();
my $total = 0;

foreach $counter (@numbers) {
    if (($numbers[$counter] % 3 == 0) or ($numbers[$counter] % 5 == 0)) {
        push (@all_array, $numbers[$counter]);
    }
}

pop (@all_array);    #after that the last digit is still in place
pop (@all_array);    # only now the number 1000 is removed

my $tot = eval join ' ', @all_array;      #returns correct value
print $tot;
  

Последний элемент массива равен 1000. Кажется, что за ним следует пробел, поэтому, чтобы удалить число и получить правильный результат, я должен использовать функцию pop дважды. Использование локального $»=» ничего не меняет. Кроме того, я получаю сообщение: Использование неинициализированного значения в @numbers по модулю (%) при C:UsersGregDocumentsperlunt.pl строка 10.
Что я делаю не так и как это исправить?

Комментарии:

1. Для перебора символов @number, foreach $counter (0..$#number) . У вас есть псевдоним $ counter для каждого элемента в @number по очереди (что сработало бы, если бы вы использовали просто $ counter вместо $ numbers [$counter] везде в вашем теле цикла)

2. Спасибо @Dillon. Использование foreach foreach $counter (0..$#numbers) решило проблему.

3. Возможно, вы отметили не того человека — я просто отредактировал ваш пост для форматирования. Я думаю, вы хотели пометить @ysth

Ответ №1:

Давайте пройдемся по вашему коду:

  • @numbers это массив с числами от 1 до 1000
    • Почему вы включаете 1000 в список, когда в упражнении написано «меньше N»?
  • цикл for
    • присваивает каждому из чисел значение $counter , т. е. 1, 2, …
    • вы используете $counter в качестве индекса в @numbers
      • зачем вы это делаете, когда $counter уже есть число, которое вы ищете?
      • Массивы Perl начинаются с индекса 0, поэтому у вас ошибка «один за другим»
      • вы никогда не проверяете, 1 потому что ваше первое число будет $numbers[1] == 2 (ОК, не приводит к неправильному результату для текущей задачи …)
      • вы получаете доступ к одному элементу, находящемуся за в массиве, т.е. $numbers[1000] == undef
    • вычисление с undef вызовет предупреждение
    • undef % 3 == 0 верно, следовательно…
  • первый pop() удалит undef (из $counter == 1000 )
  • второй pop() удалит 1000 (из $counter == 999 )
  • тогда вы используете eval для строки 3 5 6 ... очень неэффективный способ выполнения суммы 🙂

Не было бы просто более простым подходом для вычисления суммы при прохождении по числам от 1 до N-1? F.пример.:

 #!/usr/bin/perl
use strict;
use warnings;

foreach my $arg (@ARGV) {
    my $sum = 0;

    foreach my $number (1..$arg - 1) {
        $sum  = $number
            if ($number % 3 == 0) || ($number % 5 == 0);
    }

    print "${arg}: ${sum}n";
}

exit 0;
  

Тестовый запуск:

 $ perl dummy.pl 10 100 1000 10000
10: 23
100: 2318
1000: 233168
10000: 23331668
  

Комментарии:

1. или просто $sum = List::Util::sum grep $_ % 3 == 0 || $_ % 5 == 0, 1..999

2. Спасибо @Stefan. Гораздо более приятное решение, чем мое. И, наконец, я понимаю, почему у меня было undef в последнем элементе. Большое спасибо!