How to print 'AND' between array elements? - arrays

If I have an array with name like below.
How do I print "Hi joe and jack and john"?
The algorithm should also work, when there is only one name in the array.
#!/usr/bin/perl
use warnings;
use strict;
my #a = qw /joe jack john/;
my $mesg = "Hi ";
foreach my $name (#a) {
if ($#a == 0) {
$mesg .= $name;
} else {
$mesg .= " and " . $name;
}
}
print $mesg;

Usually we use an array join method to accomplish this. Here pseudo code:
#array = qw[name1 name2 name2];
print "Hey ", join(" and ", #array), ".";

Untested:
{ local $, = " and "; print "Hi "; print #a; }

Just use the special variable $".
$"="and"; #" (this last double quote is to help the syntax coloring)
$mesg="Hi #a";

To collect the perldoc perlvar answers, you may do one of (at least) two things.
1) Set $" (list separator):
When an array or an array slice is interpolated into a double-quoted
string or a similar context such as /.../ , its elements are separated
by this value. Default is a space. For example, this:
print "The array is: #array\n";
is equivalent to this:
print "The array is: " . join($", #array) . "\n";
=> $" affects the behavior of the interpolation of the array into a string
2) Set $, (output field separator):
The output field separator for the print operator. If defined, this
value is printed between each of print's arguments. Default is undef.
Mnemonic: what is printed when there is a "," in your print statement.
=> $, affects the behavior of the print statement.
Either will work, and either may be used with local to set the value of the special variable only within an enclosing scope. I guess the difference is that with $" you are not limited to the print command:
my #z = qw/ a b c /;
local $" = " and ";
my $line = "#z";
print $line;
here the "magic" happens on the 3rd line not at the print command.
In truth though, using join is the most readable, and unless you use a small enclosing block, a future reader might not notice the setting of a magic variable (say nearer the top) and never see that the behavior is not what is expected vs normal performance. I would save these tricks for small one-offs and one-liners and use the readable join for production code.

Related

How to type selected elements of an array in double quotes

Here, I'm trying to print the 2nd, 3rd and 4th elements of an array in double quotes and I've only been able to do it in single quotes.
my #fruits = ("apples", "oranges", "guavas", "passionfruits", "grapes");
my $a = 1;
while ($a<4){
print " '$fruits[$a]' \n";
$a += 1;
}
But I can't do this in single quotes. When I change the single quotes to double quotes and vice versa, it prints "$fruits[$a]"\n three times instead.
And when I change all quotes to double quotes, it gives an error which I understand why.
Please I really need help here.
And if I could get a way to print all three elements in double quotes without having to use a loop. Thanks!
To use " in a string delimited by ", escape it.
"foo: \"$bar\"\n"
You could also switch the delimiter (keeping in mind that "..." is short for qq"...").
qq{foo: "$bar"\n}
Always use
use strict;
use warnings;
even in the shortest Perl scripts.
In case of typos in the code, Perl will usually issue errors if you include them. Without, Perl will happily do weird, wrong and pointless things silently.
Your example will not print the entire array. Instead you will get:
'oranges'
'guavas'
'passionfruits'
The first index of an array is 0 and therefore 'apples' is skipped because $a is initialized with 1. The loop is also exited due to reaching the value 4 before printing out 'grapes'.
In order to print the entire array you would do:
if you need to use the index value $i somewhere:
for my $i (0 .. $#fruits) {
print " $i: '$fruits[$i]' \n";
}
($#fruits is the last index if #fruits, equal to the the size of the array minus 1. Since this array has 5 items, the index values range from 0 to 4)
otherwise:
foreach my $current_fruit (#fruits) {
print " '$current_fruit' \n";
}
where $current_fruit is set to each item in the array #fruits in its turn.
Quotes in Perl function as operators, and depending on which ones you use, they may or may not do various things with the included string.
In your examples, the double quotes will do interpolation on the string, substituting the value of $fruits[$a] and replacing the escape sequence \n. Therefore:
print " '$fruits[$a]' \n";
(for $a == 1) becomes:
'oranges'
Single quotes, in contrast, will not do interpolation.
Only single quotes themselves (and backslashes preceding single quotes) need to be escaped with a backslash. (Other backslashes can optionally be escaped.) All other character sequences will appear as they are, so the argument to print in:
print ' "$fruits[$a]" \n';
is considered entirely a literal string and thus
"$fruits[$a]" \n "$fruits[$a]" \n "$fruits[$a]" \n
is printed out.
To get the desired output, there are multiple ways to go about it:
The simplest way - but not easiest to read for complex strings - is to use double quotes and escape the included quotes:
print " \"$fruits[$a]\" \n";
You can use an generic notation for "...", which is qq{...} where {} are either a pair of braces (any of (), [], {} or <>) or the same other non-whitespace, non-word character, e.g.:
print qq{ "$fruits[$a]" \n};
or
print qq! "$fruits[$a]" \n!;
You can concatenate the string out of parts that you quote separately:
print ' "' . $fruits[$a] . '"' . " \n";
Which is easiest to read in code will depend on the complexity of the string and the variables contained: For really long strings with complex dereferences, indeces and hash keys you might want to use option 3, whereas for short ones 2 would be the best.
My entire edited code:
use strict;
use warnings;
my #fruits = ("apples", "oranges", "guavas", "passionfruits", "grapes");
for my $i (0 .. $#fruits) {
print " $i: \"$fruits[$i]\" \n";
print qq< $i: "$fruits[$i]" \n>;
print ' ' . $i . ': "' . $fruits[$i] . '"' . " \n";
}
foreach my $current_fruit (#fruits) {
print " \"$current_fruit\" \n";
print qq¤ "$current_fruit" \n¤;
print ' "' . $current_fruit . '"' . " \n";
}
You can learn more about the different quotes in Perl from the perldoc (or man on UNIX-like systems) page perlop and its section titled "Quote and Quote-like Operators".

Perl matching multidimensional array elements

Im not getting any output, anyone get where the issue lies,
matching or calling?
(The two subarrays in the multidimensional array have the same length.)
//Multidimensional array,
//Idarray = Fasta ID, Seqarray = "ATTGTTGGT" sequences
#ordarray = (\#idarray, \#seqarray);
//This calling works
print $ordarray[0][0] , "\n";
print $ordarray[1][0] , "\n", "\n";
// Ordarray output = "TTGTGGCACATAATTTGTTTAATCCAGAT....."
User inputs a search string, loop iterates the sequence dimension,
and counts amount of matches. Prints number of matches and the corresponding ID from the ID dimension.
//The user input-searchstring
$sestri = <>;
for($r=0;$r<#idarray;$r++) {
if ($sestri =~ $ordarray[1][$r] ){
print $ordarray[0][$r] , "\n";
$counts = () = $ordarray[0][$r] =~ /$sestri/g;
print "number of counts: ", $counts ;
}
I think the problem lies with this:
$sestri = <>;
That may well not be doing what you intended - your comment says "user specified search string" but that's not what that operator does.
What it does, is open the filename you specifed on the command line, and 'return' the first line.
I would suggest that if you want to grab a search string from command line you want to do it via #ARGV
E.g.
my ( $sestri ) = #ARGV; # will give first word.
However, please please please switch on use strict and use warnings. You should always do this prior to posting on a forum for assistance.
I would also question quite why you need a two dimensional array with two elements in it though. It seems unnecessary.
Why not instead make a hash, and key your "fasta ids" to the sequence?
E.g.
my %id_of;
#id_of{#seqarray} = #idarray;
my %seq_of;
#seq_of{#id_array} = #seqarray;
I think this would suit your code a bit better, because then you don't have to worry about the array indicies at all.
use strict;
use warnings;
my ($sestri) = #ARGV;
my %id_of;
#id_of{#seqarray} = #idarray;
foreach my $sequence ( keys %id_of ) {
##NB - this is a pattern match, and will be 'true'
## if $sestri is a substring of $sequence
if ( $sequence =~ m/$sestri/ ) {
print $id_of{$sequence}, "\n";
my $count = () = $sequence =~ m/$sestri/g;
print "number of counts: ", $count, "\n";
}
}
I've rewritten it a bit, because I'm not entirely understanding what your code is doing. It looks like it's substring matching in #seqarray but then returning the count of matching elements in #idarray I don't think that makes sense, but if it does, then amend according to your needs.

how perl array works $"

I am confused about the outcome of this code.
my #lines;
for (my $count = 0; $count < 3; $count++) {
print "Give me input again ";
chomp (my $line = <STDIN>);
$lines[$count] = $line;
}
$" = "|";
print "#lines\n";
When I run the code, how does this: $" = "|"; work?
The results are One|Two|Three. How does the code work so that it puts "|" between each input?
It's simply what interpolation of arrays into double-quoted strings does.
"$foo\n"
is identical to
$foo . "\n"
and
"#lines\n"
is identical to
join($", #lines) . "\n"
This is documented in perldata and in perlvar.
$" is just a special variable name in perl that tells the interpreter how to separate array elements in double-quoted string context. The default value is a space, but the above code tells perl to use | instead. Hence One|Two|Three instead of the default of One Two Three if you left out that line.
See http://perldoc.perl.org/perlvar.html#General-Variables for more detail.

Ways to Flatten A Perl Array in Scalar Context

I recently started learning perl and have a question that I'm not finding a clear answer to on the Internet. say I have something like this,
#arr = (1, 2, 3);
$scal = "#arr"
# $scal is now 123.
Is the use of quotes the only way to flatten the array so that each element is stored in the scalar value? It seems improbable but I haven't found any other ways of doing this. Thanks in advance.
The join function is commonly used to "flatten" lists. Lets you specify what you want between each element in the resulting string.
$scal = join(",", #arr);
# $scal is no "1,2,3"
In your example, you're interpolating an array in a double-quoted string. What happens in those circumstances is is controlled by Perl's $" variable. From perldoc perlvar:
$LIST_SEPARATOR
$"
When an array or an array slice is interpolated into a double-quoted string or a similar context such as /.../ , its elements are separated by this value. Default is a space. For example, this:
print "The array is: #array\n";
is equivalent to this:
print "The array is: " . join($", #array) . "\n";
Mnemonic: works in double-quoted context.
The default value for $" is a space. You can obviously change the value of $".
{
local $" = ':',
my #arr = (1, 2, 3);
my $scalar = "#arr"; # $scalar contains '1:2:3'
}
As with any of Perl's special variables, it's always best to localise any changes within a code block.
You could also use join without any seperator
my $scalar = join( '' , #array ) ;
There is more than one way to do it.
in the spirit of TIMTOWTDI:
my $scal;
$scal .= $_ foreach #arr;
Read section Context in perldata. Perl has two major contexts: scalar and list.
For example:
#a = (1, 1, 1); # list context
print #a; # list context
$count = #a; # scalar context, returns the number of elements in #a
etc.

How can I print a Perl hash in specific order?

I have this code
#!/usr/bin/perl
use strict;
my #a = ("b","a","d","c");
my %h = ("a",1,"b",2,"c",3,"d",4);
#print '"' . join('","', #a), "\"\n";
print "\n";
foreach my $key (#a) {
print '"' . $h{$key} . '",';
}
print "\n";
that outputs
"2","1","4","3",
but I would like that it just outputted
"2","1","4","3"
Notice that last ',' isn't there.
Is it possible to e.g. print a hash in a specific order, or some other trick to get the output I want?
Update:
Based on friedo's answer I was able to get it right.
print '"' . join('","', #h{#a}), "\"\n";
Friedo's answer doesn't have the quotes around the values.
print join("," => map qq["$_"], #h{#a}), "\n";
At the heart of this line is #h{#a}, a hash slice that means the same as
($h{"b"}, $h{"a"}, $h{"d"}, $h{"c"})
The obvious advantage is economy of expression.
Moving out one level, we find the map operator: for each value from #h{#a}, wrap it in double quotes using qq["$_"]. Because you want double quotes in the result, the code uses qq// to switch delimiters. Otherwise, you'd be stuck with "\"$_\"" or a concatenation chain as in your question.
Finally, join inserts commas between the mapped values. In this case, => is identical to the comma operator, but I use it here instead of
join(",", ...)
which I find visually unpleasing because of the commas being crammed together.
You may be tempted to write the join without parentheses, but doing so would make "\n" an argument to join rather than print.
You can use a hash slice to get the values, then use join to stick them together with commas.
print join ",", #h{#a};
Use join to put commas between values and not at the end, and map to wrap each value in double quotes.
print join(",", map { qq|"$h{$_}"| } #a);

Resources