2017-06-09 83 views
0

我有一個字符串數組,stringarr,並且想知道最長字符串的長度。我對字符串本身不感興趣。Ruby:獲取最長字符串的長度

我的第一個解決方案是

maxlen = stringarr.max_by(&:size).size 

作品,但醜:我不得不提一下大小的兩倍,這是容易出錯,並且需要caluclated兩次最長的字符串的大小。那麼,沒有什麼大不了的字符串,但看到下面。

另一個想法是,從可讀性的角度來看

maxlen = stringarr.map(&:size).max 

清潔,但需要創建一個臨時數組。也不好。

這裏的另一種嘗試:

maxlen = stringarr.inject(0) {|memo,s| [memo.size,s.size].max} 

不完全是美麗要麼....

我不知道是否有更好的方法。我的願望是類似於

maxlen = stringarr.max_of(&:size) # Sadly no max_of in Ruby core 

當我有一個更復雜的代碼塊時,這將是特別有趣的。這當然不是很好的風格:

maxlen = measurement(stringarr.max_by {|s| measurement(s)}) 

有什麼建議嗎?

+1

你在這裏問我們什麼?你在尋找最高效的方式來做到這一點?你的意見在你的問題上是_opinions_什麼_looks_更好... – Anthony

+0

你需要字符串之後?如果沒有,你可以使用'map!',它不會創建一個「臨時數組」,它將修改現有數組。 – engineersmnky

+0

@Anthony:對於可維護且至少沒有徹底低效的解決方案,我沒有多少意見*。可維護性意味着沒有代碼重複比代碼複製更好,所以我第一次嘗試(我不得不兩次寫'size')並不是那麼好,而且低效率意味着例如對於大型數組,操作會變得很昂貴構造一個臨時數組;這就是爲什麼我的第二次嘗試不太好。所以,我不太看個人意見,但是對於可以客觀討論的結果。 – user1934428

回答

1

編譯@msergeant和@塞巴斯蒂安 - 帕爾馬:

require 'benchmark' 

N = 10_000 
stringarr = Array.new(N, 'Lorem Ipsum dolor sit amet') 

Benchmark.bm do |x| 
    x.report { stringarr.map(&:size).max } 
    x.report { stringarr.max_by(&:size).size } 
    x.report { stringarr.sort_by(&:size)[-1].size } 
    x.report { stringarr.inject(0) { |memo,s| [memo,s.size].max } } 
    x.report { stringarr.inject(0) { |memo,s| memo > s.size ? memo : s.size } } 
end 

我的贏家是@ msergeant的變種使用三元運算符,當裸[memo,s.size].max是最慢的一個。您的環境和其他stringarr的數據可能會有不同的結果。

+1

最快的解決方案是使用O(1)空間的O(n)時間:def max(arr) max = arr [0] .size arr.each {| i | max = i.size if i.size> max} max end – Anthony

3

我認爲你的inject方法可能是最乾淨的,但它有一個錯誤。你記憶大小,但你打電話.size對memoized號碼。

試試這個:

maxlen = stringarr.inject(0) {|memo,s| [memo,s.size].max} 
+0

就是你!謝謝! – user1934428

0

根據我收到的答案和評論,我決定爲此添加一個方法Enumerable。我在這裏發佈,以防有​​人想從中受益,或者相反批評它:

class Enumerable 

    # Similar to map(&block).max, but more efficient 
    # 
    # x.max_of {|s| f(s)} returns the largest value f(s), or nil if x is empty. 
    # x(seed).max_of {|s| f(s)} returns the largest value f(s), provided that it 
    #       is larger than seed, or returns seed, if no such 
    #       element exists or x is empty. 
    def max_of(seed = nil) 
    enumerator = each 
    result = nil 
    begin 
     if seed 
     result = seed 
     else 
     result = yield(enumerator.next) 
     end 
     loop do 
     next_val = yield(enumerator.next) 
     result = next_val if next_val > result 
     end 
    rescue StopIteration 
    end 
    result 
    end 

end