排序變換思路:施瓦茨變換

施瓦茨變換(Schwartzian Transform)是一種排序思路。先看看它的結構:linux

my @output_data =
    map { EXTRACTION },
    sort { COMPARISON }
    map [ CONSTRUCTION ],
@input_data;

施瓦茨變換:app

  • construction:構造一個由原始數據以及被處理後準備用來作排序屬性的元素組成的列表A
  • comparison:從列表A中取得元素進行排序,獲得排序後列表B
  • expraction:從列表B中取得原始元素獲得新列表C
  • 列表C就是期待的排序結果

先舉個例子,文件test.txt中的內容以下:函數

1     mac     2000    500
2     winxp   4000    300
3     bsd     1000    600
4     linux   1000    200
5     SUSE    4000    300
6     Debian  600     200

如今須要使用perl對該文件進行排序,以第三字段爲主排序依據(升序),第四字段(升序)、第一字段(降序)分別爲輔助排序依據。性能

下面這種代碼是誰都會的:優化

open DATA,"<","/perlapp/test.txt"
    or die "Can't open file: $!";

print sort {
                my @x = split / +/,$a;
                my @y = split / +/,$b;
                $x[2] <=> $y[2] 
                or $x[3] <=> $y[3]
                or $y[0] <=> $x[0]
           } <DATA>;

上面的排序過程當中,對每一行都進行了一次split函數處理,換句話說,每一次比較操做都進行了兩次split。code

使用施瓦茨變換,能夠將每次比較過程當中每一種函數的屢次操做都減小爲一次,正如上面的split能夠減小爲一次(性能並無更優化,只是代碼減小了,更漂亮了)。orm

如下是使用Schwartzian Transform實現上述排序需求的代碼:排序

open DATA,"<","/perlapp/test.txt" or die "Can't open file: $!";

print map { $_->[0] }
      sort { 
          $a->[3] <=> $b->[3] 
          or $a->[2] <=> $b->[2] 
          or $b->[1] <=> $a->[1] }
      map { [ $_,split / +/,$_ ] } <DATA>;

在上面施瓦茨變換代碼中(從下往上看):input

  • 最後一個map函數,將<DATA>中的元素從新構建成了一個新的匿名列表A,這個列表中除了原始文件中的每一行數據,還有對每一行進行split後的元素,由於每一行都是空格分隔的,因此split後的每個元素都直接做爲匿名列表的元素。大概以下:["6 Debian 600 200","6","Debian","600","200"]
  • sort函數對匿名列表A進行排序,取列表A中須要排序的元素進行排序,排序後獲得一個新的排序列表B,這個列表中仍然包含了原始數據和split後的各元素,只不過它們是通過排序後的
  • 第一個map函數從排序後的列表B中取出第一個元素,也就是文件中的元素數據,獲得最終的排序列表C
相關文章
相關標籤/搜索