圖元統(tǒng)計(jì)的新方法:自己寫(xiě)迭代器
在之前的幾篇有關(guān)圖元統(tǒng)計(jì)的文章中[SU-2020-08, SU-2020-11],為了能夠統(tǒng)計(jì)圖元的自定義屬性,使用了字符串轉(zhuǎn)方法名的 method_rank( obj, mtd) 方法?,F(xiàn)在看來(lái)這樣的做法還是太過(guò)于繁瑣,也實(shí)在不夠“優(yōu)雅”、不夠ruby。
因此現(xiàn)在補(bǔ)充一個(gè)更符合ruby風(fēng)格、更“優(yōu)雅”的做法。
現(xiàn)在重新回到最開(kāi)始的需求:現(xiàn)有條件是一個(gè)篩選后的圖元容器,可以 Sketchup:: Selection 類(lèi),也可以就是 Sketchup:: Entities 類(lèi),或者是通過(guò)這些容器類(lèi)重新篩選出來(lái)的 Array 類(lèi)。需要統(tǒng)計(jì)容器中的每一個(gè)元素的某一個(gè)屬性,而這些屬性可以通過(guò)其實(shí)例方法調(diào)用返回。
之前花了很大的功夫在想怎么賦予參數(shù)層次性,也就是例如 "volume. to_mm. to_mm. to_mm" 這樣的屬性應(yīng)當(dāng)如何用參數(shù)表示。但是其實(shí)完全可以就把這樣的代碼作為參數(shù)傳遞到方法中。
例如,迭代器 .each 就是一個(gè)將代碼作為參數(shù)的方法。
sels = Sketchup.active_model.selectionsels.each{|e|puts e.typename}puts sels.map(&:typename)
其中,代碼 puts e.typename 就是參數(shù),而花括號(hào)中 |e| 的聲明就將代碼中的 e 與選區(qū)的枚舉過(guò)程聯(lián)系在了一起。這樣就不需要使用諸如 sels. each2( "puts", "e.typename") 這樣的表達(dá)了。
所以關(guān)鍵就是要寫(xiě)一個(gè)類(lèi)似于迭代器的方法,這也是本篇的核心內(nèi)容。
首先嘗試以下代碼:
arr=(0..9).to_aarr.each{|i|puts i}#>> 輸出0-9p1=proc{|i|puts i}arr.each(&p1)#>> 輸出0-9p1.class#>> Proc
可以發(fā)現(xiàn),迭代器 .each 可以用中括號(hào)加代碼的形式調(diào)用,也可以用“&”加一個(gè)Proc實(shí)例的形式調(diào)用。而這里的Proc實(shí)例就能夠直接表示一段代碼。
那么,現(xiàn)在就需要知道在方法定義中,這個(gè)特殊的參數(shù)是如何調(diào)用的??梢酝ㄟ^(guò)以下代碼了解這類(lèi)參數(shù)的引用方式:
class Arraydef each2(&block)index=0while index < self.lengthblock.call(self[index])index+=1endendend
作為示范,以上代碼定義了一個(gè)可以替代 .each 方法的 .each2 方法??梢詮闹邪l(fā)現(xiàn),方法定義中每一個(gè) block. call 都會(huì)調(diào)用依次 &block 中的代碼,而如果 &block 中有形如 |i| 的自變量,就會(huì)將 .call 方法后的參數(shù)賦給 i。如果代碼中有自變量,但是 .call 方法沒(méi)有參數(shù),就會(huì)使用 nil 補(bǔ)全,多余的參數(shù)則舍棄。因此 Proc 實(shí)例也可以要求更多的自變量,就像 .sort 方法一樣。
那么統(tǒng)計(jì)圖元屬性就有了更好的選擇,甚至可以直接將這種方法寫(xiě)進(jìn) Array 類(lèi)當(dāng)中。
class Arraydef summarize(&block)h=Hash.newself.each{|i|beginres=block.call(i)rescueres="N\/A"endif h.has_key?(res) thenh[res]+=1elseh[res]=1end}return(h)endend
如下圖所示,就可以直接對(duì)選區(qū)進(jìn)行圖元統(tǒng)計(jì),圖中的 S.ss 即 Sketchup. active_model. selection。

當(dāng)然,此時(shí)的 summarize 方法只不過(guò)是返回了一個(gè)統(tǒng)計(jì)結(jié)果的哈希,如果要讓它更具可讀性,可以在 Hash 類(lèi)中追加以下方法:
class Hashdef print(reg=//)shown=0total=0self.each{|k,v|if k.to_s=~reg or reg==// thenputs "#{k}".ljust(18)+"|#{v}"shown+=1endtotal+=1}puts "------------------+----"puts "Shown:".ljust(18)+"|#{shown}" if shown!=totalputs "Total:".ljust(18)+"|#{total}"endend
在追加了這兩個(gè)方法之后就可以通過(guò)類(lèi)似于以下的代碼來(lái)統(tǒng)計(jì)圖元信息了:
sels.to_a.summarize{|i|i.definition.name}.print(/House/)以下為執(zhí)行效果:

本文編號(hào):SU-2021-02
