How can I alternate between even and odd numbers? - perl

I want the output to show which numbers are even and which are odd. Strangely, I only get 100 is odd 100 times. Does anyone know what I did wrong?
my #zahlen = (1..100);
my $zahlen = #zahlen;
foreach (#zahlen){
if (#zahlen % 2) {
print "$zahlen is even\n";
} else {
print "$zahlen is odd\n";
}
}

You are using the wrong variables in the wrong places. You set $zahlen to a constant value outside the loop (100). You can use it as the loop iterator variable instead.
Also, you should use the scalar $zahlen instead of the array #zahlen in the if statement.
use warnings;
use strict;
my #zahlen = (1 .. 10);
foreach my $zahlen (#zahlen) {
if ($zahlen % 2) {
print "$zahlen is odd\n";
}
else {
print "$zahlen is even\n";
}
}
Prints (I changed 100 to 10 to simplify the output):
1 is odd
2 is even
3 is odd
4 is even
5 is odd
6 is even
7 is odd
8 is even
9 is odd
10 is even

The code can be written in alternative more concise form
use strict;
use warnings;
use feature 'say';
my #zahlen = (1 .. 10);
say "$_ is " . (($_ % 2) ? "odd" : "even") for #zahlen;
Output
1 is odd
2 is even
3 is odd
4 is even
5 is odd
6 is even
7 is odd
8 is even
9 is odd
10 is even

Related

How to create a numeric ruler and evenly spaced numeric width markers

I am new to Perl. An exercise, where I am to create a numeric ruler from which, I size columns for data at 20 characters-width, is proving a little difficult to complete. So far, I have,
printf “%10d” x 5, (1..6);
#ruler = (1..10) x 7;
Print #ruler, “\n”;
It should look something like,
1 2 3 4
1234567890123456789012345678901234567890
What I get for the top row of numbers is an error, ‘Redundant argument in printf at <script.pl> line #; the bottom row produces numbers from 1 to 10, as it ought with the range operator, but I would like it to produce 1 to 9 with a zero on the end. I did think to start the range from 0, but I haven’t figured out how to remove the first index and only the first index.
I would be grateful for your guidance with both issues.
The warning is due to the fact that you pass 6 numbers to printf, but the format only requires 5.
To me,
1 2 3 4
1234567890123456789012345678901234567890
reads as
11, 12, 13, ..., 19, 10, 21, 22, 23, ...
Why does it start with 11? Why is 10 between 19 and 21?
The following makes more sense:
1 2 3 4
01234567890123456789012345678901234567890 0-based
and
1 2 3 4
1234567890123456789012345678901234567890 1-based
I'm not going to give the solution outright.
If you want the numbers 1 to 9 and 0, that would be 1..9, 0.
%10d will add padding on the left. %-10d will add padding on the right.
Nothing says you can't prefix the output with something that doesn't repeat, like a zero or a space.
Provided desired output starts count from 11 instead 1 -- it doesn't look right.
Perhaps OP intended to start count from 1 until some $max value with placing a digit representing tens above main counter.
Please study following code sample for compliance with your requirements.
use strict;
use warnings;
use feature 'say';
my $max = shift || 45;
rule($max);
sub rule {
my $max = shift;
my($a,$b);
$a .= ' ' x 9 . $_ for 1..$max/10;
$b .= $_ % 10 for 1..$max;
say $a . "\n" . $b;
}
Output
1 2 3 4
123456789012345678901234567890123456789012345
Original OP's code requires slight modification to achieve desired output
use strict;
use warnings;
use feature 'say';
my $max = shift || 45;
printf "%10d" x int($max/10) . "\n", (1..$max/10);
print $_ % 10 for 1..$max;
print "\n";

Project Euler Number 1 perl

I am a beginner coder and I have started doing the Project Euler stuff from projecteuler.net, and am on problem #1. The problem is:
If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.
Find the sum of all the multiples of 3 or 5 below 1000.
I have the following code too:
#!/usr/bin/perl
use strict;
use warnings;
my $a;
my $b;
my $c = 0;
my $d = 0;
my $e;
for ($a= 0; $a < 1000; $a += 3 ) {
$d = $d + $a;
}
for ($b= 0; $b < 1000; $b += 5 ) {
$c = $c + $b;
}
$e = $c + $d;
printf "$e \n";
And my output is this:
266333
But I know for a fact that is wrong. Maybe it's going over common answers that 5 and 3 share, like 15 or 45.
Whatever it is, suggestions?
If two loops are involed, they both need some conditions inside to skip some iteration. Perhaps you could also think about an alternative solution using only one loop:
for (my $n = 1; $n < 1000; $n++) {
if ( ... ) { # <--*
$d += $n;
}
}
It could be easier and less code repeatition.
Now we only need to figure out the key expression for that if statement. :-)
Maybe it's going over common answers that 5 and 3 share, like 15 or 45
Yes that's exactly what's happening. You will need to prevent common multiples from being added to the total sum twice. Perhaps adding a conditional statement in one of your loops. (I'd rather not give out the exact answer and let you figure out how to do it)
I think you're doing too much in one stage. Don't add the numbers as you go. Instead, get a list of the numbers that you're interested in and add them all up at the end.
Oh, and here's a little hint. If you're trying to store a list of things and you want no duplications - then the keys of a hash work great for that.

need to use pop function twice to remove last element from the array (perl)

I've just started to learn Perl and joined Euler project to practice coding. This is the first exercise I did. The task was: "If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23. Find the sum of all the multiples of 3 or 5 below 1000." My solution:
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;
The final element of the array is 1000. It seems as if it is followed by a space so to remove the number and get the correct result I have to use the pop function twice. The use of local $"='' changes nothing. Besides, I'm getting a message: Use of uninitialized value within #numbers in modulus (%) at C:\Users\Greg\Documents\perl\unt.pl line 10.
What am I doing wrong and how to fix it?
Let's go through your code:
#numbers is an array with the numbers from 1 to 1000
Why do you include 1000 in the list when the exercise says "less than N"?
the for loop
assigns each of the numbers to $counter, i.e. 1, 2, ...
you use $counter as index into #numbers
why do you do that when $counter is already the number you are looking for?
Perl arrays start at index 0, so you have an off-by-one error
you never check 1 because your first number will be $numbers[1] == 2 (OK, doesn't cause an incorrect result for the task at hand...)
you access one element behind the array, i.e. $numbers[1000] == undef
calculating with undef will cause a warning
undef % 3 == 0 is true, hence...
the first pop() will remove undef (from $counter == 1000)
the second pop() will remove 1000 (from $counter == 999)
then you use eval on a string 3 + 5 + 6 + ... a very inefficient way to do a sum :-)
Wouldn't it be just a simpler approach to calculate the sum while running over the numbers from 1 to N-1? F.ex.:
#!/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;
Test run:
$ perl dummy.pl 10 100 1000 10000
10: 23
100: 2318
1000: 233168
10000: 23331668

perl better method for counting each array element occurance

I have 2 arrays, one is the root array, which contains huge mount of elements. Another is the tested array, all of which elements is a subset of root array. I want to construct a new array, with size equal to root arrays, and its element value at a specific position represents the count of that element in the tested array.
Below codes works well when 2 array size is small. But the practical problem I meet is that, the root arrays has about 15000 elements, and there are about 14000 tested arrays.
I wonder to have better algorithm. Do you guys have some suggestions?
my #root=qw(1 2 3 4 5 6 7 8 10);
my #aa=qw(1 1 2 3);
my #count;
foreach my $eleroot(#root){
my $mathnum=0;
my ($i) = grep { $root[$_] ~~ $eleroot } 0 .. $#root;
foreach my $eleaa(#aa){
if ($eleroot==$eleaa){
$mathnum++;
}
}
$count[$i]=$mathnum;
}
print #count;
A better algorithm would be to use a hash to keep counts. For your sample arrays, it would look like this. (And will run considerably faster than your solution).
#!/usr/bin/perl
use strict;
use warnings;
my #root=qw(1 2 3 4 5 6 7 8 10);
my #aa=qw(1 1 2 3);
print join("\t", #root), "\n";
my %seen;
for my $data (#aa) {
$seen{$data}++;
}
print join("\t", map {$_ // '0'} #seen{#root}), "\n";
Output is:
1 2 3 4 5 6 7 8 10
2 1 1 0 0 0 0 0 0
#seen{#root} is a hash slice keyed by the #root array. If no item was found for any of the #root elements, the map supplies a zero.
The map {$_ // '0'} portion is saying pass to join a count if $_ has a count otherwise pass a zero.

print the number which is present in documentA but absent in documentB

I've a problem in making a Perl program for matching the numbers in two documents. Let's say there are documents A and B.
So I want to have the numbers which is present in document A and absent in the document B.
Example 1:
DocA: 1 2 3 5 6 8 9 10 11 12 13
DocB: 1 2 3 6 7 8 9 10 11
output:
5 12 13
EDITED:
#a=qw( 1 2 3 5 6 8 9 10 11 12 13);
#b=qw( 1 2 3 4 5 6 7 8 9 10 11);
#new=();
#new1=();
for($i=0;$i<=$#a;$i++)
{
for($j=0;$j<=$#b;$j++)
{
if($a[$i] ne $b[$j])
{
push(#new,$b[$j]);
}
}
}
You could use the CPAN module Array::Utils. The following will do what you need:
use Array::Utils qw(:all);
my #a = qw( 1 2 3 5 6 8 9 10 11 12 13);
my #b = qw( 1 2 3 4 5 6 7 8 9 10 11);
my #diff = array_minus(#a, #b);`
By the way, the reason your program does not work is because you made a logic error. You are adding a value to #new EVERY TIME the value does not match. So, in the first iteration of the loop you compare the a value to the b value. Even though the value is equal to the first element of #b, it is not equal to the other ten elements of #b and hence all of these elements are added to #new. I have rewritten your loop. Note the more Perlish loops instead of the C-loop you used in your code.
my #a = qw( 1 2 3 5 6 8 9 10 11 12 13);
my #b = qw( 1 2 3 4 6 7 8 9 10 11);
my #new = ();
for my $a_value (#a) {
my $b_not_in_a = 1;
INNER: for my $b_value (#b)
{ if($a_value == $b_value) {
$b_not_in_a = 0;
last INNER; }
}
if ($b_not_in_a)
{
push(#new,$a_value);
}
}
Consider Algorithm::Diff ?
You could use a hash. Read DocA and initialize a hash using the read numbers as keys:
open(INPUT, "DocA");
while (<INPUT>)
{
chomp;
$myhash{$_} = 1;
}
Then read DocB and foreach number, check if already defined in your hash:
open(INPUT, "DocB");
while (<INPUT>)
{
chomp;
if (not defined $myhash{$_})
{
print "$_\n";
}
}
This code asumes you have a number per line. If your files are formatted differently, you will need to adapt it.
This code will work even if your numbers aren't ordered.
The lists in your example are sorted. I am assuming that they are, and that you're not allowed to use modules since it is homework. Also, since it is homework, I won't give the answer, but some hints in the right direction.
If you would do this by hand, and you are only allowed to look at the front of each row, how would you do it? If the head of A is a number smaller than B, what does that mean? If it is equal, what does that mean? If it is larger, what does that mean?
Now you know how you can handle one situation, from that you can create some kind of step to reduce the problem. Now define when you need to stop, and what the possible leftovers of the lists are at that point, and how you can get your answer from the values you collected in the step, and the remainder after you stop.
Some examples of extreme cases:
#a = qw();
#b = qw(1 2 3);
#a = qw (1 2 3);
#b = qw (4 5 6);
#a = qw(1 3 5);
#b = qw(2 4 6)
Good luck!