2017-06-09 47 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