How to check if an array has an element that's not Integer? - perl

For example, I have an array = [1,2,3,4,5,a,#,4]
how can I check if an array has an element that's not integer?
If an array has an element that's not integer than I am planning to fail the script which is die function.

Type::Tiny provides a quick method (all) to check if all elements in a list match a specific type consrtaint.
use strict; use warnings; use feature qw( say );
use Types::Common qw( Int PositiveInt );
my #array = ( 1, 2, 3, "foo" );
if ( not Int->all( #array ) ) {
say "They're not all integers";
}
if ( PositiveInt->all( #array ) ) {
say "They're all positive integers";
}
# Another way to think about it:
my $NonInteger = ~Int;
if ( $NonInteger->any( #array ) ) {
say "There's at least one non-integer";
}

If quick&dirty is good enough:
my #a = (1,2,3,-4,0,5,4," -32 ");
die if grep { !defined or !/^\s*-?\d+\s*$/ } #a;
This however doesn't handle for example valid integers (in Perl) such as "1_200_499" or "0e0" well.

Related

How to print data in column form in Perl?

I have a program that prints the contents of arrays in rows. I would like it to print each array in a column next to each other.
This is the code:
#!/usr/local/bin/perl
use strict;
use warnings;
my #M_array;
my #F_array;
open (my $input, "<", 'ssbn1898.txt');
while ( <$input> ) {
chomp;
my ( $name, $id ) = split ( /,/ );
if ( $id eq "M" ) {
push ( #M_array, $name );
}
else {
push ( #F_array, $name );
}
}
close ( $input );
print "M: #M_array \n";
print "F: #F_array \n";
Is this possible or am I trying to do something that can't be done?
Desired format:
M F
Namem1 Namef1
Namem2 Namef2
You can add whatever separator you would like between your data by using the join function, the example below formats the data in your array separated by tabs:
...
use List::MoreUtils qw/pairwise/;
my $separator = "\t";
print join($separator, qw(M F)), "\n";
print join(
"\n",
pairwise { ( $a // '') . $separator . ( $b // '') } #M_array, #F_array
), "\n";
...
I think, you should use Perl formats. Have a look at the Perl documentation. You may want to use the #* format field in your case.
I extended your code in order to print the desired output at the end
use strict;
use warnings;
my #M_array;
my #F_array;
open (my $input, "<", 'ssbn1898.txt');
while ( <$input> ) {
chomp;
my ( $name, $id ) = split ( /,/ );
if ( $id eq "M" ) {
push ( #M_array, $name );
}
else {
push ( #F_array, $name );
}
}
close ( $input );
unshift #M_array, 'M';
unshift #F_array, 'F';
my $namem;
my $namef;
my $max = 0;
$max = (length($_) gt $max ? length($_) : $max) for #M_array;
my $w = '#' . '<' x $max;
eval "
format STDOUT =
$w #*
\$namem, \$namef
.
";
while ( #M_array or #F_array) {
$namem = shift #M_array || '';
$namef = shift #F_array || '';
write;
}
join is probably the simplest approach to take tabs will align your columns nicely.
join ( "\t", #array ),
Alternatively, perl allows formatting via (s)printf:
printf ( "%-10s %-10s", "first", "second" );
Or a more detailed 'format'
Given what you're trying to do is put your two arrays into columns though:
#!/usr/local/bin/perl
use strict;
use warnings;
my $format = "%-10s\t%-10s\n";
my #M_array = qw ( M1 M2 M3 M4 M5 );
my #F_array = qw ( F1 F2 F3 );
my $maxrows = $#M_array > $#F_array ? $#M_array : $#F_array;
printf ( $format, "M", "F" );
for my $rownum ( 0..$maxrows ) {
printf ( $format, $M_array[$rownum] // '', $F_array[$rownum] // '' );
}
This will print a header row, and then loop through you arrays printing one line at a time. // is a conditional operation that tests if something is defined. It's only available in newer perls though*. In older versions || will do the trick - it's almost the same, but handles '' and 0 slightly differently.
* Perl 5.10 onward, so is pretty safe, but worth mentioning because some system are still rocking around with perl 5.8 on them.
You may format output with the sprintf function, but there are some more problems to solve: What if the arrays don't have the same count of entries? For this, you need a place-holder. How much letters must fit into a column? How should it be aligned? Some code for illustration:
#!/usr/bin/perl
use strict;
use warnings;
my #m = (1, 2, 3);
my #f = (11, 22, 33, 44);
# calculate how many rows to display
my $max = #m;
if (#m < #f) {
$max = #f;
}
# placeholder for missing data
my $none = '-';
# formatting 20 chars per column, left aligned
my $fmt = "%-20s%-20s\n";
# print header
print sprintf($fmt, "M", "F");
# print data rows
foreach my $i (0..$max-1) {
print sprintf($fmt, ($m[$i] or $none), ($f[$i] or $none));
}
If you are interested in more sophisticated formatting (for instance center-aligned text), you should switch to the special formatting capabilities Perl provides for report generation.
Borrowing from #HunterMcMillen
use strict;
use warnings;
use feature "say";
local $, = "\t"; # separator when printing list
my $i = (#F_array > #M_array) ? $#F_array : $#M_array;
say qw(M F);
say $M_array[$i] //"", $F_array[$i] //"" for 0 .. $i;
I guess Text::Table is the required module which comes with the perl distribution(just need to install).Go through the below documentation -
Documentation of Text::Table
You need to pass the content as array to the add() method and it will do the wonders for you.

Checking whether a string does not present in hash

I want to perform a check with the following condition.
If the member of %ans is not contained in %test, print that value of %ans.
But why this didn't print it?
use Data::Dumper;
my %ans = ("foo" => 1);
my %test = ("bar" => 1);
foreach my $ansrule ( keys %{$ans} ) {
if ( !exists $test{$ansrule} ) {
print "ANS: $ansrule\n";
}
}
https://eval.in/51453
Because keys %{$ans} is not the same as keys %ans, and you should've used the latter:
$ans and %ans are different variables.
The %{$ans} attempts to dereference a hash ref stored in $ans variable - which is, apparently, not defined. Have you added use strict; to your code, you'd have seen the warning...
Global symbol "$ans" requires explicit package name
You want
foreach my $ansrule ( keys %ans )
instead of
foreach my $ansrule ( keys %$ans )
use strict; use warnings; would be helpful in detection of such flaws.

How can I find out if elements of an array match any elements of another array?

if I have a hash
my %foo = ( foo => 1, bar => 1 );
I want to check if any key of %foo is in a comparison array (and obviously keys %foo is just an array ). I keep thinking some weird syntax that does't exist like.
my #cmp0 = qw( foo baz );
my #cmp1 = qw( baz blargh );
if keys %foo in #cmp0 # returns true because key foo is in the array
if keys %foo in #cmp1 # returns false because no key in foo is an element of cmp1
What is the simplest way to do this?
List::MoreUtils has a function called any that uses a syntax similar to grep, but stops its internal loop the first time the criteria are met. The advantage to this behavior is that far fewer iterations will be required (assuming random distribution of intersections).
An additional advantage of any is code clarity: It is named for what it does. Perl Best Practices discourages using grep in Boolean context because the assumed use for grep is to return a list of elements that match. It works in Boolean context, but the intent of the code is less clear to a reader than any, which is designed specifically for Boolean usage.
It is true that any adds a dependency on List::MoreUtils. However, List::MoreUtils is one of those modules that is so ubiquitous, it is highly likely to already be installed.
Here's an example:
use List::MoreUtils qw( any );
my %foo = ( foo => 1, bar => 1 );
my #cmp0 = qw( foo baz );
my #cmp1 = qw( baz blargh );
print "\#cmp0 and %foo have an intersection.\n"
if any { exists $foo{$_} } #cmp0;
print "\#cmp1 and %foo have an intersection.\n"
if any { exists $foo{$_} } #cmp1;
Another option is the ~~ Smart Match Operator, which became available in Perl 5.10.0 and newer. It could be used like this:
my %foo = ( foo => 1, bar => 1 );
my #cmp0 = qw( foo baz );
my #cmp1 = qw( baz blargh );
print "\#cmp0 and %foo have an intersection.\n" if #cmp0 ~~ %foo;
print "\#cmp1 and %foo have an intersection.\n" if #cmp1 ~~ %foo;
With smartmatch, you eliminate the List::MoreUtils dependency in favor of a minimum Perl version dependency. It's up to you to decide whether the code is as clear as any.
The tidiest way to write this is to use grep together with the exists operator.
This code
my %foo = ( foo => 1, bar => 1 );
my #cmp0 = qw( foo baz );
my #cmp1 = qw( baz blargh );
print "YES 0\n" if grep { exists $foo{$_} } #cmp0;
print "YES 1\n" if grep { exists $foo{$_} } #cmp1;
gives this output
YES 0
grep is a good idea, and probably the cleanest. You can however also use the logical OR assignment operator ||=:
my $found;
$found ||= exists $foo{$_} for #cmp1;
These are simple set operations.
use strictures;
use Set::Scalar qw();
⋮
my $foo = Set::Scalar->new(keys %foo);
$foo->intersection(Set::Scalar->new(#cmp0))->size; # 1
$foo->intersection(Set::Scalar->new(#cmp1))->size; # 0
There are - as usual - more ways to solve this. You could do it like this:
#!/usr/bin/perl
use strict ;
use warnings ;
my %hash = ( foo => 1 , bar => 1 ) ;
my %cmp = ( cmp0 => [ qw(foo baz) ] ,
cmp1 => [ qw(baz blargh) ] ) ;
my #hash_keys = keys %hash ;
foreach my $compare ( keys %cmp ) {
my %tmp ;
# Generate a temporary hash from comparison keys via hash slice
#tmp{#{$cmp{$compare}}} = undef ;
INNER:
foreach my $hash_key ( #hash_keys ) {
if( exists $tmp{$hash_key} ) {
printf "Key '%s' is part of '%s'.\n" , $hash_key , $compare ;
last INNER ;
}
}
}
This gives:
Key 'foo' is part of 'cmp0'.

How can I find the indices where two arrays differ in value?

I would like to find out which element has changed between two arrays that contains same data inside it.
#prev=("0","1","0","1");
#curr=("0","1","0","0");
From the above two arrays clearly the last element of the array has changed.
How will I know that only a particular element has changed and rest all of them should not have changed, given that I know which index of the array should change?
To find out the indices where the values have changed:
my #indices_of_change = grep { $prev[$_] ne $curr[$_] } 0 .. $#prev;
e.g. with:
my #prev = ( 0, 1, 0, 1 );
my #curr = ( 0, 1, 0, 0 ); # #indices_of_change == ( 3 );
Of course, there are several caveats attached:
Are #curr and #prev supposed to be the same length? What is the expected behavior if they are not?
The context of DWIM needs to be clarified. Are strings expected to be inside the array(s)? Is '00' supposed to equal to '0'?
If you don't mind me pimping my own module, this is exactly why Array::Compare was written.
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Array::Compare;
my #prev = qw(0 1 0 1);
my #curr = qw(0 1 0 0);
my $cmp = Array::Compare->new;
my #diffs = $cmp->full_compare(\#prev, \#curr);
say "Difference at these indexes: #diffs";
You can use the zip function from List::MoreUtils to allow comparison like this. Using zip has the advantage that it works with arrays that are not of equal length.
use List::MoreUtils qw/zip/;
my #changed =
map { $_[0] != $_[1] }
zip #prev, #curr;
You can use Data::Difference to compare arrays. And it's quite easy to mangle the returned diff to your needs:
use strict;
use warnings;
use Data::Difference qw(data_diff);
use Data::Dumper;
my #prev = ( "0", "1", "0", "1" );
my #curr = ( "0", "1", "0", "0" );
my #diff = data_diff ( \#prev, \#curr );
my #indices_of_change = map { #{ $_->{ 'path' } } } #diff;
print Dumper ( \#indices_of_change );

In Perl, how can I find the index of a given value in an array?

$VAR1 = [
'830974',
'722065',
'722046',
'716963'
];
How can I calculate the array index for the value "722065"?
The firstidx function from List::MoreUtils can help:
use strict;
use warnings;
use List::MoreUtils qw(firstidx);
my #nums = ( '830974', '722065', '722046', '716963' );
printf "item with index %i in list is 722065\n", firstidx { $_ eq '722065' } #nums;
__END__
item with index 1 in list is 722065
using List::Util, which is a core module, unlike List::MoreUtils, which is not:
use List::Util qw(first);
my #nums = ( '830974', '722065', '722046', '716963' );
my $index = first { $nums[$_] eq '722065' } 0..$#nums;
Here is how you would find all the positions at which a given value appears:
#!/usr/bin/perl
use strict;
use warnings;
my #x = ( 1, 2, 3, 3, 2, 1, 1, 2, 3, 3, 2, 1 );
my #i = grep { $x[$_] == 3 } 0 .. $#x;
print "#i\n";
If you only need the first index, you should use List::MoreUtils::first_index.
If you only need to look up the one item, use firstidx as others have said.
If you need to do many lookups, build an index.
If your array items are unique, building an index is quite simple. But it's not much more difficult to build one that handles duplicate items. Examples of both follow:
use strict;
use warnings;
use Data::Dumper;
# Index an array with unique elements.
my #var_uniq = qw( 830974 722065 722046 716963 );
my %index_uniq = map { $var_uniq[$_] => $_ } 0..$#var_uniq;
# You could use hash slice assinment instead of map:
# my %index_uniq;
# #index_uniq{ #var_uniq } = 0..$#var_uniq
my $uniq_index_of_722065 = $index_uniq{722065};
print "Uniq 72665 at: $uniq_index_of_722065\n";
print Dumper \%index_uniq;
# Index an array with repeated elements.
my #var_dupes = qw( 830974 722065 830974 830974 722046 716963 722065 );
my %index_dupes;
for( 0..$#var_dupes ) {
my $item = $var_dupes[$_];
# have item in index?
if( $index_dupes{$item} ) {
# Add to array of indexes
push #{$index_dupes{$item}}, $_;
}
else {
# Add array ref with index to hash.
$index_dupes{$item} = [$_];
}
}
# Dereference array ref for assignment:
my #dupe_indexes_of_722065 = #{ $index_dupes{722065} };
print "Dupes 722065 at: #dupe_indexes_of_722065\n";
print Dumper \%index_dupes;
Here's hastily written attempt at a reverse look-up using a hash.
my $VAR1 = [ '830974', '722065', '722046', '716963' ];
my %reverse;
$reverse{$VAR1->[$_]} = $_ for 0 .. #$VAR1 - 1;
print $reverse{722065};
This does not account for arrays with duplicate values. I do not endorse this solution for production code.
check out the Perl FAQ
use strict;
use Data::Dumper;
sub invert
{
my $i=0;
map { $i++ => $_ } #_;
}
my #a = ('a','b','c','d','e');
print Dumper #a;
print Dumper invert #a;