#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
в последнем элементе. Большое спасибо!