test_STM.pl
# Schwartzian Transform Method
# First Section --- Difinition of @LIST ---
# Difinition of @LIST
@LIST = ('1,21,4' ,
'5,33,43' ,
'15,2,5' ,
'12,15,21');
print "@LIST\n";
# Second Section --- Get Refference of each line in @LIST ---
# For each elements in @LIST
foreach (@LIST){
# Split now-specificated element in @LIST by ",".
# In @tmp, there are 3 elements. These are values.
my @tmp = split(/,/,$_);
# Get @tmp's refference by "[ ]".
# In @tmp, there are 3 elements. These are refferences.
my @tmp = [@tmp];
# Add them to @tmp_LIST
# In @tmp_LIST, 3 elements added each times. These are refferences.
push @tmp_LIST,@tmp;
}
print "@tmp_LIST\n";
# Forrowing is the same working
# map{} gets forrowing array and returns the result of the statement in { }.
# @tmp_LIST = map{[split(/,/,$_)]} @LIST;
# print "@tmp_LIST\n";
# Third Section --- Sort @LIST by using derefference of @tmp_LIST ---
# $a and $b is refference of @LIST.
# And derefference them by operator ->[]. So $a->[2] and $b->[2] are values themselves.
# Sort them by values. Rewrite @tmp_LIST.
# Sort gets a forrowing array and returns a value of the array by criterion in {}.
# In @tmp_LIST, there are 4 elements. These are refferences.
#@tmp_LIST = sort{$a->[2] cmp $b->[2]} @tmp_LIST;
# If sorting them by number is needed, forrowing is sutable.
@tmp_LIST = sort{$a->[2] <=> $b->[2]} @tmp_LIST;
print "@tmp_LIST\n";
# Fourth Section --- Join them ---
# For each elements in @tmp_LIST
foreach(@tmp_LIST){
# Get values themselves refferenced by $_.
my @tmp = @$_;
# Join each elements in @tmp by ",".
my @tmp = join(',',@tmp);
# Add them to @NEW_LIST.
push @NEW_LIST,@tmp;
}
print "@NEW_LIST\n";
# Forrowing is the same working
#@NEW_LIST = map{join',',@$_} @tmp_LIST;
#print "@NEW_LIST\n";
# All sections can be written in one line.
# Forrowing is One line style about upper sections.
#@NEW_LIST = map{join',',@$_} sort{$a->[2] cmp $b->[2]} map{[split',']} @LIST;
#@NEW_LIST = map{join',',@$_} sort{$a->[2] <=> $b->[2]} map{[split',']} @LIST;
#print "@NEW_LIST\n";
例えば下のようにするとa.dat中の1カラムにxの値、2カラムに二次関数の値がセットされるんだな。
C:\>perl -le "sub f{($a,$b,$c)=(rand,rand,rand);return $a*$_**2+$b*$_+$c;} for(-9..9){$x=$_+rand;$f=&f($x);print \"$x $f\";}">a.dat
C:\>
結果を表示すると下のようになるんだな。
C:\>perl -le "@a=<>; print @a;" a.dat -8.77401733398438 72.4348754882813 -7.83602905273438 5.97018432617188 -6.059326171875 35.9939270019531 -5.44882202148438 33.2612609863281 -4.21817016601563 9.92474365234375 -3.3221435546875 -1.31829833984375 -2.09671020507813 3.02935791015625 -1.600341796875 2.762939453125 -0.749908447265625 0.922332763671875 0.154327392578125 0.6827392578125 1.42169189453125 2.23629760742188 2.8875732421875 2.50311279296875 3.66021728515625 7.56057739257813 4.10379028320313 19.9759826660156 5.96383666992188 5.775146484375 6.0418701171875 17.5700378417969 7.32489013671875 35.4329223632813 8.97604370117188 31.3730163574219 9.09332275390625 29.8526916503906 C:\>
これを上の方法を使って2カラム目でソートしてみるんだな。
C:\>perl -le "@a=<>; @b=map{join' ',@$_}sort{$a->[1]<=>$b->[1]}map{[split/\s/]}@a; for(@b){print}" a.dat
-3.3221435546875 -1.31829833984375
0.154327392578125 0.6827392578125
-0.749908447265625 0.922332763671875
1.42169189453125 2.23629760742188
2.8875732421875 2.50311279296875
-1.600341796875 2.762939453125
-2.09671020507813 3.02935791015625
5.96383666992188 5.775146484375
-7.83602905273438 5.97018432617188
3.66021728515625 7.56057739257813
-4.21817016601563 9.92474365234375
6.0418701171875 17.5700378417969
4.10379028320313 19.9759826660156
9.09332275390625 29.8526916503906
8.97604370117188 31.3730163574219
-5.44882202148438 33.2612609863281
7.32489013671875 35.4329223632813
-6.059326171875 35.9939270019531
-8.77401733398438 72.4348754882813
C:\>
たったこれだけでソートできてしまうんだな。キモはmap{}を使うとこなんだな。これを使うとforeach{}文で配列にpushするような場合のスクリプトを短く書けるんだな。