Perl - printing output after a for loop - perl

I have this code where I have problem getting the output I want:
print OUT1 "$first[0]\t$first[1]\t$first[2]\t";
for my $index1 (3..8)
{
my $ratio1 = sprintf( "%.4f%s", $numerator/$denominator,"\t");
#print OUT1 "$ratio1";
$variable1 = "$ratio1"; # problem with this line
}
print OUT1 "$variable1"; # print to textfile
print OUT1 "\n";
I am trying to print out the output after it run finish the for loop 6 times (3 to 8). The data should arrange something like this:
Desired output (e.g.):
A B C 4 4 4 4 4 4
C D F 2 6 5 8 3 1
G H I 6 1 2 4 7 0
Instead, it print out only the last column:
A B C 4
C D F 1
G H I 0
so I change to this line by adding the "." to join the 6 columns together
$variable1 .= "$ratio1"; # problem with this line
and I get weird output like this:
A B C 4 4 4 4 4 4
A B C 4 4 4 4 4 4 2 6
A B C 4 4 4 4 4 4 2 6 4
A B C 4 4 4 4 4 4 2 6 4 6
A B C 4 4 4 4 4 4 2 6 4 6 1 ...
Is there anything wrong with my code somewhere?

Yes, you need to declare and initialize your $variable1 before your for loop
print OUT1 "$first\t$second\t$third\t";
my $variable1 = '';
for my $index1 (3..8)
{
$variable1 .= sprintf( "%.4f%s", $numerator/$denominator,"\t");
}
print OUT1 "$variable1"; # print to textfile
Alternatively, you could avoid a temporary buffer, and just print within the for loop

Related

How I can use printf or disp in MATLAB to print some special format of my data set?

I have a data set with 5 columns and 668 rows. I need to use these data in ampl and I need a special format of it as the following :
1 3 4 5 7
5 4 3 2 1
4 5 6 4 3
4 5 3 4 2
[*,*,1]: 1 2 3 4:=
4 3 2 1 5
4 5 6 7 4
3 4 5 6 7
3 4 2 3 1
[*,*,2]: 1 2 3 4:=
4 5 6 2
4 3 2 1
4 5 3 2
1 2 7 1
[*,*,3]: 1 2 3 4:=
.
.
.
In other words, I have to print 4 rows then [*,*, i]: 1 2 3 4:= again 4 rows and that statement and so on. It should be done by a simple for loop but I don't know how to do that since I don't work with MATLAB.
You can a string with disp combined with a for loop.
num2str is used to convert number to string.
For example with a matrix containing 100 lines.
D = rand(100,4);
for i = 1 : 4 : size( D,1 )
disp( D( i : i + 3,: ) )
disp(['[*,*,' num2str((i + 3)/4) ']: 1 2 3 4:='])
end

Reorder Table Rows and columns Matlab

I have a 5x5 table:
a b c d e
a 1 2 3 4 5
b 3 5 7 2 6
c 1 3 4 6 1
d 4 4 1 7 8
e 6 7 2 1 6
where the headers are the strings.
I want to know how to reorder the table rows and columns using the headers
so for example of I wanted them to be in this order e b c a d then this will be the table:
e b c a d
e 6 7 2 6 1
b 6 5 7 3 2
c 1 3 4 1 6
a 5 7 3 1 4
d 8 4 1 4 7
Let the table be defined as
T = table;
T.a = [1 3 1 4 6].';
T.b = [2 5 3 4 7].';
T.c = [3 7 4 1 2].';
T.d = [4 2 6 7 1].';
T.e = [5 6 1 8 6].';
And let the new desired order be
order = {'e' 'b' 'c' 'a' 'd'};
The table can be reordered using just indexing:
[~, ind] = ismember(order, T.Properties.VariableNames);
T_reordered = T(ind,order);
Note that:
To reorder only columns you'd use T_reorderedCols = T(:,order);
To reorder only rows you'd use T_reorderedRows = T(ind,:);
So in this example,
T =
a b c d e
_ _ _ _ _
1 2 3 4 5
3 5 7 2 6
1 3 4 6 1
4 4 1 7 8
6 7 2 1 6
T_reordered =
e b c a d
_ _ _ _ _
6 7 2 6 1
6 5 7 3 2
1 3 4 1 6
5 2 3 1 4
8 4 1 4 7
Here is a way to do it using indexing. You can indeed re-arrange the rows and columns using indices as you would for any array. In this case, I substitute each letter in the headers array with a number (originally [1 2 3 4 5]) and then, using a vector defining the new order [5 2 3 1 4], re-order the table. You could make some kind of lookup table to automate this when you deal with larger tables:
clc
clear
a = [1 2 3 4 5;
3 5 7 2 6;
1 3 4 6 1;
4 4 1 7 8;
6 7 2 1 6];
headers = {'a' 'b' 'c' 'd' 'e'};
%// Original order. Not used but useful to understand the idea... I think :)
OriginalOrder = 1:5;
%// New order
NewOrder = [5 2 3 1 4];
%// Create table
t = table(a(:,1),a(:,2),a(:,3),a(:,4),a(:,5),'RowNames',headers,'VariableNames',headers)
As a less cumbersome alternative to manually creating the table with the function table, you can use (thanks to #excaza) the function array2table which saves a couple steps:
t = array2table(a,'RowNames',headers,'VariableNames',headers)
Either way, re-arrange the table using the new indices:
New_t = t(NewOrder,NewOrder)
Output:
t =
a b c d e
_ _ _ _ _
a 1 2 3 4 5
b 3 5 7 2 6
c 1 3 4 6 1
d 4 4 1 7 8
e 6 7 2 1 6
New_t =
e b c a d
_ _ _ _ _
e 6 7 2 6 1
b 6 5 7 3 2
c 1 3 4 1 6
a 5 2 3 1 4
d 8 4 1 4 7

concatenate each Row with another row in matlab?

I've a matrix 4X4 trying to concatenate rows like this :
1 with 2
1 with 3
1 with 4
2 with 3
2 with 4
3 with 4
at the end I have 6 even rows separately
Dear ((thefourtheye )) ,this Below is output of final code I will repeat one row if you can review
newline =
1 1 1 1
2 2 2 2
3 3 3 3
4 4 4 4
newline =
1 1 1 1
2 2 2 2
4 4 4 4
5 5 5 5
newline =
1 1 1 1
2 2 2 2
5 5 5 5
6 6 6 6
newline =
2 2 2 2
3 3 3 3
4 4 4 4
5 5 5 5
newline =
2 2 2 2
3 3 3 3
5 5 5 5
6 6 6 6
newline =
3 3 3 3
4 4 4 4
5 5 5 5
6 6 6 6
more or less manually...
new = [old(1,:) old(2,:); old(1,:) old(3,:); old(1,:) old(4,:); old(2,:) old(3,:); old(2,:) old(4,:); old(3,:) old(4,:)]
but you should write a function if you need to repeat in other scenarios
% Your original array is yourmat, it is square
newmat = [];
for n=1:length(yourmat)
for m=n+1:length(yourmat)
newline = yourmat(n, :) + yourmat(m, :); % Is this what you meant by concatenate?
newmat = [newmat; newline];
end
end
You should be able to easily do this with nested for loops and then store them however you want, but I chose to just store them into a cell array
someMatrix = rand(4)
storage = {}
iter = 1
newMatrix = zeros(2,length(someMatrix));
for ii = 1:length(someMatrix)
for jj = i+1:length(someMatrix)
newMatrix(1,:) = someMatrix(ii,:);
newMatrix(2,:) = someMatrix(jj,:);
storage{iter} = newMatrix
iter = iter + 1;
end
end

Conditionally replacing cell values with column names

I have a 165 x 165 rank matrix such that each row has values ranging from 1-165. I want to parse each row and delete all values >= 5, sort each row in increasing order, then replace the values 1-5 with the name of the column from the original matrix.
For example, for row k the values 1 ,2 3, 4, 5, would result after the first two transformations and would be replaced by p,d, m, n, a.
I am assuming that your array consists of an array of arrays...
Neither Awk, Sed, or Perl have multi-dimensional arrays. However, they can be emulated in Perl by using arrays of arrays.
$a[0]->[0] = xx;
$a[0]->[1] = yy;
[...]
$a[0]->[164] = zz;
$a[1]->[0] = qq;
$a[1]->[1] = rr;
[...]
$a[164]->[164] = vv;
Does this make sense?
I'm calling the row $x and columns $y, so an element in your array will be $array[$x]->[$y]. Is that good?
Okay, your column names will be in row $array[0], so if we find a value less than five in $array[$x]->[$y], we know the column name is in $array[0]->[$y]. Is that good?
for my $x (1..164) { #First row is column names
for my $y (0..164) {
if ($array[$x]->[$y] <= 5) {
$array[$x]->[$y] = $array[0]->[$y];
}
}
}
I'm simply going through all the rows, and for each row, all the columns, and checking the value. If the value is less than or equal to five, I replace it with the column name.
I hope I'm not doing your homework for you.
This GNU sed solution might work although it will need scaling up as I only used a 10x10 matrix for testing purposes:
# { echo {a..j};for x in {1..10};do seq 1 10 | shuf |sed 'N;N;N;N;N;N;N;N;N;s/\n/ /g';done; }> test_data
# cat test_data
a b c d e f g h i j
4 5 9 3 6 2 10 8 7 1
3 7 4 2 1 6 10 5 8 9
10 9 3 1 2 7 8 5 6 4
5 10 4 9 7 8 1 3 6 2
8 6 5 9 1 4 3 2 7 10
2 8 9 3 5 6 10 1 4 7
3 9 8 2 1 4 10 6 7 5
3 7 2 1 8 6 10 4 5 9
1 10 8 3 6 5 4 2 7 9
7 2 3 5 6 1 10 4 8 9
# cat test_data |
sed -rn '1{h;d};s/[0-9]{2,}|[6-9]/0/g;G;s/\n|$/ &/g;s/$/&1 2 3 4 5 /;:a;s/^(\S*) (.*\n)(\S* )(.*)/\2\4\1\3/;ta;s/\n//;s/0[^ ]? //g;:b;s/([1-5])(.*)\1(.)/\3\2/;tb;p'
j f d a b
e d a c h
d e c j h
g j h c a
e h g f c
h a d i e
e d a f j
d c a h i
a h d g f
f b c h d
The sed command works as follows.
The first line of the data file contains the column headings is stored in the hold space then the pattern space (current line) is deleted. For all subsequent data lines all two or more digit numbers and values 6 to 9 are converted to 0. The column names are appended, along with a newline to the data values. Spaces are inserted before the newline and end of string. The data is transformed into a lookup and the sorted values i.e.. 1 2 3 4 5 is prepended to it. The newline is removed along with any 0 values and associated lookups. The values 1 to 5 are replaced by the column names in the lookup.
EDIT:
I may have misunderstood the problem regarding sorting columns or rows, if so it's a minimal fix - replace 1 2 3 4 5 by the original values and perform a numeric sort prior to replacing the numeric data with column names from the lookup.

How can I correctly calculate the lengths of fields in a CSV dcoument using Perl?

I have a datas et and like to do a simple while operation with a Perl script.
Here is a small extraction from the dataset:
"number","code","country","gamma","X1","X2","X3","X4","X5","X6"
1,"DZA","Algeria","0.01",7.44,47.3,0.46,0,0,0.13
2,"AGO","Angola","0.00",6.79,"NULL",0.21,1,0,0.28
3,"BEN","Benin","-0.01",7.02,38.9,0.27,1,0,0.05
4,"BWA","Botswana","0.06",6.28,45.7,0.42,1,0,0.07
5,"HVO","Burkina Faso","0.00",6.15,36.3,0.08,1,0,0.05
6,"BDI","Burundi","0.00",6.38,41.8,0.18,1,0,0
The script should count the length of every , separated field and store the highest values
into an array.
However, the saving doesn't work properly. Here is a part of the code:
#maxl = map length, #terms;
while(`<INFILE>`) {
$_ =~ s/[\"\n]//g ;
#terms = split/$sep/, $_;
#lengths = map length, #terms;
for($k = 0, $k <= $#terms, $k++) {
if($lengths[$k] > $maxl[$k]) {
$maxl[$k] = $lenghts[$k];
}
}
print "#lengths\n";
}
Now the #maxl uses an earlier part from the code where it uses the second line of the dataset.
When I use a print command just to see the values of the #maxl operation i get:
1 3 7 4 4 4 4 1 1 5
In the while loop I used another print statement just to see the other values, I get:
1 3 6 4 4 4 4 1 1 4
1 3 5 5 4 4 4 1 1 4
1 3 8 4 4 4 4 1 1 4
1 3 12 4 4 4 4 1 1 4
1 3 7 4 4 4 4 1 1 1
1 3 8 4 4 4 4 1 1 4
1 3 10 4 4 4 4 1 1 4
1 3 16 5 4 4 4 1 1 4
2 3 4 5 3 4 4 1 1 4
2 3 7 4 4 4 4 1 1 4
2 3 5 4 4 4 4 1 1 4
2 3 5 4 4 4 4 1 1 4
2 3 8 4 4 4 4 1 1 4
2 3 5 4 4 4 1 1 1 4
The fourth column eg has obviously values which are greater than 3. The while loop was supposed to save the greatest values and substitute those values into #maxl.
What went wrong?
...in the for loop the comma are wrong
for($k = 0, $k <= $#terms, $k++)
however, after cleaning that up there still seems to be a problem...
there's a typo here
$maxl[$k] = $lenghts[$k];
for starters (which 'use strict' would have caught)
consider using Text::CSV for more reliable parsing of comma-separated data (it can also handle other separators):
#!/usr/bin/perl
use strict;
use warnings;
use Text::CSV;
my $csv = Text::CSV->new();
my #max_lengths;
while ( my $line = <INFILE> ) {
die "Unable to parse '$line'" unless $csv->parse($line);
my #column_lengths = map { length } $csv->fields();
for my $i ( 0 .. $#column_lengths ) {
if ( $column_lengths[$i] > ($max_lengths[$i] || 0) ) {
$max_lengths[$i] = $column_lengths[$i];
}
}
}
print "MAX LENGTHS OF EACH FIELD: #max_lengths\n";