i am generating 20 numbers and then i am shuffling it
perl -e 'foreach(1..20){print ",$_ "} '
| perl -MList::Util=shuffle -F',' -lane 'print shuffle #F'
and the output is:-
19 15 11 9 8 13 18 4 2 7 5 20 10 14 3 16 1 17 6 12
Now i want the output something like this:-
19 15 11 9
8 13 18 4
2 7 5 20
...
Any help will be appreciated
Doing that in several steps on the command line is ... strange. You can just do it in one program.
use strict;
use warnings;
use List::Util 'shuffle';
my $count = 1;
foreach my $i ( shuffle 1 .. 20) {
print "$i ";
print "\n\n" unless $count++ % 4;
}
This shuffles the list of 1 to 20 directly and then prints each item, but prints two linebreaks after every four. The % is the modulo operator that returns the left-over from a division by 4. So whenever the $count is divisible by 4, it returns 0, and the print kicks in. On the command line it would be like this:
$ perl -MList::Util=shuffle -e '$c=0; for (shuffle 1..20) { print"$_ "; print "\n\n" unless $c++%4}'
Here's the output:
11 20 8 17
10 18 19 6
1 14 7 5
13 16 4 3
9 2 15 12
You could also use a splice call to chop the result of the shuffle list up as you want and print it that way if you didn't want to code an explicit counter. Something like this:
perl -MList::Util=shuffle -e '#list=shuffle(1..20); while (#ret_line = splice(#list, 0, 4)) {print "#ret_line\n\n"}'
I'd put the numbers into an array and use splice to remove them in blocks of four:
use strict;
use warnings 'all'
use List::Util 'shuffle';
my #nums = shuffle 1 .. 20;
print join(" ", splice #nums, 0, 4), "\n\n" while #nums;
Related
I am trying to:
Populate 10 elements of the array with the numbers 1 through 10.
Add all of the numbers contained in the array by looping through the values contained in the array.
For example,
it would start off as 1, then the second number would be 3 (1 plus 2), and then the next would be 6 (the existing 3 plus the new 3)
This is my current code
#!/usr/bin/perl
use warnings;
use strict;
my #b = (1..10);
for(#b){
$_ = $_ *$_ ;
}
print ("The total is: #b\n")
and this is the result
The total is: 1 4 9 16 25 36 49 64 81 100
What im looking for is:
The total is: 1 3 6 10 etc..
The shown sequence has for each element: its index + 1 + value at the previous index
perl -wE'#b = 1..10; #r = 1; $r[$_] = $_+1 + $r[$_-1] for 1..$#b; say "#r"'
The syntax $#name is for the last index in the array #name.
If the array is changed in place, as shown, then there is no need to initialize
perl -wE'#b = 1..10; $b[$_] = $_+1 + $b[$_-1] for 1..$#b; say "#b"'
Both print
1 3 6 10 15 21 28 36 45 55
As a script
use warnings;
use strict;
use feature 'say';
my #seq = 1..10;
for my $i (1..$#seq) {
$seq[$i] = $i+1 + $seq[$i-1];
}
say "#seq";
$ perl -E'say "The total is: ",join" ",map$sum+=$_,1..10'
The total is: 1 3 6 10 15 21 28 36 45 55
I have the following code. I am trying to print all common values from #arr2 and #arr4 without repetition. The expected output should be 5,6,7,8,9,13,14,15,16,17,18. I am not getting how to put a condition in a loop to avoid repetition and why $i is not printing in this code.
#!/usr/bin/perl
my #arr2 = ( 1 .. 10, 5 .. 15, 10 .. 20 );
my #arr4 = ( 5 .. 9, 13 .. 18 );
foreach my $line1 (#arr2) {
my ( $from1, $to1 ) = split( /\.\./, $line1 );
#print "$to1\n";
foreach my $line2 (#arr4) {
my ( $from2, $to2 ) = split( /\.\./, $line2 );
for ( my $i = $from1; $i <= $to1; $i++ ) {
for ( my $j = $from2; $j <= $to2; $j++ ) {
if ( $i == $j ) {
print "$i \n";
}
}
}
}
}
As Jonathan has pointed out, you appear to misunderstanding the nature of your data because you don't recognize the Range Operator .. used to construct lists.
my #array = (1 .. 10);
print "#array\n";
Outputs
1 2 3 4 5 6 7 8 9 10
Once you recognize that, then you just need to be pointed to the following:
perlfaq4 - How can I remove duplicate elements from a list or array?
perlfaq4 - How do I compute the difference of two arrays? How do I compute the intersection of two arrays?
Combined to form:
#!/usr/bin/perl
use strict;
use warnings;
my #arr2 = ( 1 .. 10, 5 .. 15, 10 .. 20 );
my #arr4 = ( 5 .. 9, 13 .. 18 );
my %seen;
$seen{$_}++ for uniq(#arr2), uniq(#arr4);
my #intersection = sort { $a <=> $b } grep { $seen{$_} == 2 } keys %seen;
print "#intersection\n";
sub uniq {
my %seen;
$seen{$_}++ for #_;
return keys %seen;
}
Outputs:
5 6 7 8 9 13 14 15 16 17 18
The first step to understanding your problem is to understand your data — the arrays do not hold what you think they hold.
#!/usr/bin/perl
my #arr2=(1..10,5..15,10..20);
my #arr4=(5..9,13..18);
print "arr2: #arr2\n";
print "arr4: #arr4\n";
The output from this is:
arr2: 1 2 3 4 5 6 7 8 9 10 5 6 7 8 9 10 11 12 13 14 15 10 11 12 13 14 15 16 17 18 19 20
arr4: 5 6 7 8 9 13 14 15 16 17 18
This shows that your code trying to split a string on .. is going to fail horribly.
One of the most basic debugging techniques is printing out the data you've actually got to ensure it matches what you think you should have. Here, that basic printing would have shown that the input data is not in the format you expected.
i have extracted the following data in a file
0..5
8..10
12..16
but these are not working as range function. i have stored these in an array.
#arr=('0..5,8..10,12..16');
after printing the array it gives
0..5
8..10
12..16
but i need output as
0 1 2 3 4 5
8 9 10
12 13 14 15 16
am not getting where is the problem. why the stored data (..) is not working as range. function
You're starting with string representations of ranges, not actual perl ranges.
To get a perl array, you must convert your data. You could use eval like others have recommended. However, that's like using a machete to perform a haircut.
Instead, I'd advise using more precision tools to extract the range boundaries from the string and then build your new data structure. Using split or a regex could easily pull the values. The following does so using the latter:
use strict;
use warnings;
while (<DATA>) {
chomp;
my ($start, $end) = /(\d+)/g;
my #array = ($start .. $end);
print "#array\n";
}
__DATA__
0..5
8..10
12..16
Outputs:
0 1 2 3 4 5
8 9 10
12 13 14 15 16
Addendum for multiple entries on a row
The following allows for multiple ranges to be on a single row. Note, I'm using split in this version for the sake of variety, although I could have easily used a regex as well:
use strict;
use warnings;
while (<DATA>) {
chomp;
my #array;
for my $range (split ' ') {
my ($start, $end) = split /\.{2}/, $range, 2;
push #array, ($start .. $end);
}
print "#array\n";
}
__DATA__
0..5
4..9 14..18
8..10
12..16
Outputs:
0 1 2 3 4 5
4 5 6 7 8 9 14 15 16 17 18
8 9 10
12 13 14 15 16
Data is data. Perl does not evaluate data as Perl (i.e. expand .. range operator) unless you explicitly tell it to with eval. The following debug session should clarify things for you.
$ perl -de0
Loading DB routines from perl5db.pl version 1.33
Editor support available.
Enter h or `h h' for help, or `man perldebug' for more help.
main::(-e:1): 0
DB<1> #arr = ('0..5,8..10,12..16')
DB<2> p #arr
0..5,8..10,12..16
DB<3> eval "#arr = ('0..5,8..10,12..16')"
DB<4> p #arr
0..5,8..10,12..16
DB<5> #arr = ('0..5','8..10','12..16')
DB<6> p #arr
0..58..1012..16
DB<7> #arr = eval "(0..5,8..10,12..16);"
DB<8> x #arr
0 0
1 1
2 2
3 3
4 4
5 5
6 8
7 9
8 10
9 12
10 13
11 14
12 15
13 16
DB<9>
If you want Perl to expand string ranges into Perl ranges, you must eval that data.
use strict;
use warnings;
use feature qw(say);
my #arr=('0..5','8..10','12..16');
foreach my $range (#arr) {
say join ' ', eval ($range);
}
__END__
0 1 2 3 4 5
8 9 10
12 13 14 15 16
Try this to store the values in the array:
#arr=((0..5),(8..10),(12..16));
Each iteration in my perl code generates a vector of 5.
Output of first iteration is
out1
1
2
3
4
5
The second iterations generates same length of vector.
out2
10
20
30
40
50
and then it runs for nth time
out n
100
200
300
400
500
I want to merge these columns and have the final output in a tabular format or matrix format if you like:
out1 out2 ... outn
1 10 100
2 20 200
3 30 300
4 40 400
5 50 500
I tried splitting and then using the push but it prints "(101" and only do it once and not for all 20. I also have no idea where the "(101" comes from.
Any suggestions?
First, put all those output lists to a list. Second, iterate on that list: output every first element of each element-list in the first iteration, output every second element of each element-list in the second iteration, and so on.
For example
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
my #lists;
for my $i (1..10) {
my #list;
push #list, $_ * $i for (1..5);
push #lists, \#list;
}
$Data::Dumper::Indent = 0;
print Dumper(\#lists), "\n\n";
while (#{$lists[0]}) {
for my $list (#lists) {
print shift #$list, "\t";
}
print "\n";
}
Output:
$ perl t.pl
$VAR1 = [
[1,2,3,4,5],
[2,4,6,8,10],
[3,6,9,12,15],
[4,8,12,16,20],
[5,10,15,20,25],
[6,12,18,24,30],
[7,14,21,28,35],
[8,16,24,32,40],
[9,18,27,36,45],
[10,20,30,40,50]
];
1 2 3 4 5 6 7 8 9 10
2 4 6 8 10 12 14 16 18 20
3 6 9 12 15 18 21 24 27 30
4 8 12 16 20 24 28 32 36 40
5 10 15 20 25 30 35 40 45 50
Note: The output of Data::Dumper has been edited to make it more compact.
Save your vector information to an array of array as you do your processing. Then you can output the rows using a simple join:
use strict;
use warnings;
my #rows;
for my $i (1..10) {
my #vector = map {$i * $_} (1..5);
push #{$rows[$_]}, $vector[$_] for (0..$#vector);
}
for my $row (#rows) {
print join(" ", map {sprintf "%-3s", $_} #$row), "\n";
}
Outputs:
1 2 3 4 5 6 7 8 9 10
2 4 6 8 10 12 14 16 18 20
3 6 9 12 15 18 21 24 27 30
4 8 12 16 20 24 28 32 36 40
5 10 15 20 25 30 35 40 45 50
Note: It'd be a lot easier to advise if you provided code and actual data.
I wrote a program that load the data from a 2 columns file, made an algorithm calculation and then write the pair of elements in the file that have this coefficient and put them into an array called #blackPair. I would like to iterate N times the algorithm taking the datas from the file but not those that are in the #blackPair array.
I thought of something like this:
#!/usr/bin/perl
use strict;
use warnings;
use feature 'say';
my $iter;
my $startNode;
my $endNode;
my %k;
my %end;
my %node;
my %edge;
my #blackPair=();
my $counts=0;
my $inputfile = "file3";
################# DATA ABSORTION
open(DAT,$inputfile) || die("Could not open file!");
while(<DAT>)
{
my ($entry) = $_;
chomp($entry);
my ($startNode, $endNode) = split(/ /,$entry);
$k{$endNode}++;
$k{$startNode}++;
$edge{$startNode}{$endNode}=1;
$edge{$endNode}{$startNode}=1;
}
################# ALGORITHM
my $minCentrality=2;
foreach my $i (keys %edge) {
foreach my $j (keys %{$edge{$i}}){
my #couple =($j,$i);
if($i<$j){
if (($k{$i}-1) !=0 && ($k{$j}-1) !=0){
my $triangleCount=0;
#couple=($i,$j) if ($k{$i}<$k{$j});
foreach (keys %{$edge{$couple[0]}}){
$triangleCount++ if exists $edge{$couple[1]}{$_};
}
my $centrality=($triangleCount+1)/($k{$couple[0]}-1);
if ($centrality<$minCentrality){
$minCentrality=$centrality;
#blackPair=#couple;
}
}
}
}
}
foreach (#blackPair){
say;
}
Close(DAT);
The file is the following:
1 2
1 3
1 4
1 5
1 6
1 9
2 3
4 5
5 9
6 7
6 8
6 16
7 8
9 10
9 11
10 11
10 12
10 14
11 12
11 13
12 13
12 14
14 15
16 17
16 18
17 18
17 19
18 19
18 20
19 20
The first pair that appear in the #blackPair are the 6 and 1. After found them I would like that the program restart the search but avoiding to charge into the array the pairs 1 and 6. Doing that the second pair would be 6 and 16. I would like to repeat this process N times (for example N = 4). I thought to put before the while(<DAT>) in the "DATA ABSORTION" another while(counts<=4){ and inside the while(<DAT>) an if(<DATA> != #blackPair){. There is what I thought
while(counts <= 4) {
while(<DAT>)
{
if(<DAT> != #blackPair){
my ($entry) = $_;
chomp($entry);
.....
}
#### ALGORITHM
counts++;
}
But it doesn't work. Any help?
After 4 iteration, in the #blackPair there should be the following pairs:
6 1
16 6
9 1
9 5
<DAT> != #blackPair is definitely not what you want.
!= is for numerical comparison. You want to do either string comparison (the ne operator) or maybe use the smart match operator to check for list membership (~~ \#blackPair)
but using the right operator won't really help you, because #blackPair already has mangled the input data (#blackPair might contain the elements (6,1), corresponding to an original input line of "1 6\n")
Instead, how about updating your graph in each iteration?
for my $count (1..4) {
my $minCentrality = 2;
...
say join " ", #blackPair;
# now update the graph
delete $edge{$blackPair[0]}{$blackPair[1]};
delete $edge{$blackPair[1]}{$blackPair[0]};
$k{$blackPair[0]}--;
$k{$blackPair[1]}--;
} # next iteration