2015-09-06 240 views
2

我正在尋找一種腳本,方法或工具來對嵌套的降價列表進行排序。我使用崇高的文本,它有一個內置的排序行功能,但是這個函數破壞了任何嵌套列表的順序。舉例來說,如果我想排序:排序嵌套Markdown列表?

* Zoo Animals 
    * Herbivores 
     * Zebra 
     * Gazelle 
    * Carnivores 
     * Tiger 
     * Lion 
    * Omnivores 
     * Gorilla 
     * Baboon 
     * Chimpanzee 
* Domestic Animals 
    * Canines 
     * German Shepherd 
     * Cocker Spaniel 

用崇高的排序線功能,我得到:

 * Baboon 
     * Chimpanzee 
     * Cocker Spaniel 
     * Gazelle 
     * German Shepherd 
     * Gorilla 
     * Lion 
     * Tiger 
     * Zebra 
    * Canines 
    * Carnivores 
    * Herbivores 
    * Omnivores 
* Domestic Animals 
* Zoo Animals 

顯然,這不是我想要的。我要的是一個「之類的作用域」的排序相對於每一顆子彈的水平,而不會破壞嵌套的關係,就像這樣:

* Domestic Animals 
    * Canines 
     * Cocker Spaniel 
     * German Shepherd 
* Zoo Animals 
    * Carnivores 
     * Lion 
     * Tiger 
    * Herbivores 
     * Gazelle 
     * Zebra 
    * Omnivores 
     * Baboon 
     * Chimpanzee 
     * Gorilla 

這裏的一些事情,我已經研究過我的意念,每個:

  • 使用sublime包進行排序。我找不到一個。但是,也許有一種方法可以使用CSSComb包並將其調整爲一個降價列表?
  • 使用sublime中的手動過程對列表進行排序,可能是通過選擇項目符號級別並按這些排序進行排序?這樣做的問題是要排序的行的選擇必須處於相同的縮進級別,並且不能被另一個縮進級別的其他行分隔開,否則排序會完全混亂。除非我錯過了什麼?
  • 使用腳本對行進行排序。我熟悉ruby,所以也許有辦法將這個列表導入到ruby中,並將嵌套列表視爲沿着this post的嵌套散列。我確信我可以用ruby腳本來實現我的目標,但是如果已經有了解決方案,我不想走這條路。

你將如何去排序一個大的嵌套降價清單?

更新#1:

@ J4G創建解決了原來的排序問題,看他的答案的鏈接有很大的Atom包。

上一個列表是一個沒有代碼塊和編號列表的簡單列表。然而,排序現實生活中的降價名單的時候,我們有一些代碼塊和編號列表和線開始有特殊字符 - 嵌套在列表中,像這樣:

* Commands 
    * Migrations 
     * `rake db:migrate` - push all migrations to the database 
     * 'STEP=3' - revert the last 3 migrations 
    * `Rails` 
     * `c` - start rails console, run code from your app! 
    * `Rake` 
     * Rake Task 
     ```ruby 
     desc 'process csv' 
     task process_csv: :environment do 
      Node.process_csv 
     end 
     ``` 
* Package Upgrade Status: 
    1. Install Package 
    2. Attach Plugin 
    3. Review Installation 
    ~~~ 
    |Install|Status| 
    |Yes|Pending| 
    ~~~ 

排序後,我會覺得上面的降價名單應該返回因爲刻度線和引號沒有排序的意義,並且代碼塊/編號列表已經按照正確的順序創建。

+1

看起來沒有被任何人解決。如果你願意,我可以非常快速地在Node中寫一個。 – Harangue

回答

2

如果你是有興趣使用Atom(我強烈建議它作爲Sublime的免費替代品),我只是做了一個包來做你需要的。

https://atom.io/packages/markdown-sort-list

+1

這似乎是執行所需排序比使用Ruby或其他通用腳本語言更好的方法。 –

3

這是您可以用Ruby做到的一種方法。假設字符串由變量str保存。

代碼

def sort_indented(str) 
    arr = str.lines.map { |s| [indentation(s), s.chomp] } 
    indent_offset = arr.map(&:first).uniq.sort.each_with_index. 
    with_object({}) { |(indent, i),h| h[indent] = i } 
    dim_size = indent_offset.size 
    prev = [] 
    arr.map do |indent, s| 
    a = ['']*dim_size 
    offset = indent_offset[indent] 
    a[offset] = s 
    a[0,offset] = prev.first(offset) 
    prev = a 
    a 
    end.sort.map { |a| a[a.rindex { |s| s != '' }] }.join("\n") 
end 

def indentation(s) 
    s[/^\s*/].size 
end 

str =<<THE_END 
* Zoo Animals 
    * Herbivores 
     * Zebra 
     * Gazelle 
    * Carnivores 
     * Tiger 
     * Lion 
    * Omnivores 
     * Gorilla 
     * Baboon 
     * Chimpanzee 
* Domestic Animals 
    * Canines 
     * German Shepherd 
     * Cocker Spaniel 
THE_END 

在Ruby此構造用於定義字符串文字被稱爲 「here document」,或 「在這裏的文檔」。

puts sort_indented(str) 

* Domestic Animals 
    * Canines 
     * Cocker Spaniel 
     * German Shepherd 
* Zoo Animals 
    * Carnivores 
     * Lion 
     * Tiger 
    * Herbivores 
     * Gazelle 
     * Zebra 
    * Omnivores 
     * Baboon 
     * Chimpanzee 
     * Gorilla 

一般方法

當紅寶石排序數組的數組,如:

a = [1,2,4] 
b = [4,5,6] 
c = [1,2,3,5]] 
[a, b, c] 

它將在前排序每個陣列的第一個元素。由於ac在偏移量零處具有相同的元素1,並且b在該偏移處具有4,所以ac都將在排序後的數組中出現在b之前。 Ruby看着ac的第二個元素打破平局。因爲他們都等於2,紅寶石進入第三個元素,其中的平局被打破:ca之前,因爲3 < 4

我會arr轉換成下面的數組:

result =  
[["* Zoo Animals"  , ""    , ""], 
["* Zoo Animals"  , " * Herbivores", ""], 
["* Zoo Animals"  , " * Herbivores", "  * Zebra"], 
["* Zoo Animals"  , " * Herbivores", "  * Gazelle"], 
["* Zoo Animals"  , " * Carnivores", ""], 
["* Zoo Animals"  , " * Carnivores", "  * Tiger"], 
["* Zoo Animals"  , " * Carnivores", "  * Lion"], 
["* Zoo Animals"  , " * Omnivores" , ""], 
["* Zoo Animals"  , " * Omnivores" , "  * Gorilla"], 
["* Zoo Animals"  , " * Omnivores" , "  * Baboon"], 
["* Zoo Animals"  , " * Omnivores" , "  * Chimpanzee"], 
["* Domestic Animals", ""    , ""], 
["* Domestic Animals", " * Canines" , ""], 
["* Domestic Animals", " * Canines" , "  * German Shepherd"], 
["* Domestic Animals", " * Canines" , "  * Cocker Spaniel"]] 

一旦以這種形式,我們可以排序:

result.sort 
    #=> [["* Domestic Animals", "", ""], 
    # ["* Domestic Animals", " * Canines", ""], 
    # ["* Domestic Animals", " * Canines", "  * Cocker Spaniel"], 
    # ["* Domestic Animals", " * Canines", "  * German Shepherd"], 
    # ["* Zoo Animals", "", ""], ["* Zoo Animals", " * Carnivores", ""], 
    # ["* Zoo Animals", " * Carnivores", "  * Lion"], 
    # ["* Zoo Animals", " * Carnivores", "  * Tiger"], 
    # ["* Zoo Animals", " * Herbivores", ""], 
    # ["* Zoo Animals", " * Herbivores", "  * Gazelle"], 
    # ["* Zoo Animals", " * Herbivores", "  * Zebra"], 
    # ["* Zoo Animals", " * Omnivores", ""], 
    # ["* Zoo Animals", " * Omnivores", "  * Baboon"], 
    # ["* Zoo Animals", " * Omnivores", "  * Chimpanzee"], 
    # ["* Zoo Animals", " * Omnivores", "  * Gorilla"]] 

的最後一步是提取從每個最後一個非空字符串排序數組的元素。

詳解

首先我們定義一個輔助方法來計算一個字符串的縮進:

def indentation(s) 
    s[/^\s*/].size 
end 

例如,

  #1234 
indentation(" * Herbivores") 
    #=> 4 

現在讓字符串轉換爲線陣列:

a = str.lines 
    #=> ["* Zoo Animals\n", 
    # " * Herbivores\n", 
    # "  * Zebra\n", 
    # "  * Gazelle\n", 
    # " * Carnivores\n", 
    # "  * Tiger\n", 
    # "  * Lion\n", 
    # " * Omnivores\n", 
    # "  * Gorilla\n", 
    # "  * Baboon\n", 
    # "  * Chimpanzee\n", 
    # "* Domestic Animals\n", 
    # " * Canines\n", 
    # "  * German Shepherd\n", 
    # "  * Cocker Spaniel\n"] 

接下來,我們轉換a到對一個陣列,所述一對被的a(字符串)的元件的第二元件,與所述換行砍掉結束時,第一個是它的縮進:

arr = a.map { |s| [indentation(s), s.chomp] } 
    # => [[0, "* Zoo Animals"],  [4, " * Herbivores"], 
    #  [8, "  * Zebra"],  [8, "  * Gazelle"], 
    #  [4, " * Carnivores"],  [8, "  * Tiger"], 
    #  [8, "  * Lion"],  [4, " * Omnivores"], 
    #  [8, "  * Gorilla"], [8, "  * Baboon"], 
    #  [8, "  * Chimpanzee"], [0, "* Domestic Animals"], 
    #  [4, " * Canines"],  [8, "  * German Shepherd"], 
    #  [8, "  * Cocker Spaniel"]] 

事實上,我們會一步執行前兩個操作:

arr = str.lines.map { |s| [indentation(s), s.chomp] } 

接下來,我們需要知道所使用的縮進:

indents = arr.map { |pair| pair.first } 
    #=> [0, 4, 8, 8, 4, 8, 8, 4, 8, 8, 8, 0, 4, 8, 8] 

,我們可以寫更多的經濟是這樣的:

indents = arr.map(&:first) 

要查找唯一縮進我們寫:

unique = indents.uniq 
    #=> [0, 4, 8] 

如果他們不是爲了,我們應該對它們進行排序:

sorted = unique.sort 
    #=> [0, 4, 8] 

這三個縮進中的每一個都將對應我們要排序的數組中的偏移量,所以構造一個散列很方便:

indent_offset = sorted.each_with_index.with_object({}) do |(indent, i),h| 
    h[indent] = i 
end 
    #=> {0=>0, 4=>1, 8=>2} 

同樣,我們可以通過組合幾個步驟執行此計算:

indent_offset = arr.map(&:first).uniq.sort.each_with_index. 
    with_object({}) { |(indent, i),h| h[indent] = i } 

接下來我們取代的arr每個元素與串的3個元素數組:

dim_size = indent_offset.size 
    #=> 3 
prev = [] 
result = arr.map do |indent, s| 
    a = ['']*dim_size 
    offset = indent_offset[indent] 
    a[offset] = s 
    a[0,offset] = prev.first(offset) 
    prev = a 
    a 
end 

結果這個計算是我在上面給出的第一個數組。現在,我們可以排序result獲得我下一般方法給了第二陣:

sorted = result.sort 

最後兩個步驟來替換最後一個非空字符串sorted每個元素(一個三元素的數組) :

sorted_strings = sorted.map { |a| a[a.rindex { |s| s != '' }] } 

再加入這些字符串成一個字符串:

sorted_strings.join("\n") 
+0

哇,非常徹底的答案!也許這一天可以變成紅寶石寶石。 – singularity

+0

謝謝,但我希望已經有一個更好的Ruby gem。當我寫這篇文章的時候,我認爲Ruby應該是一個更好的方法。 –