Ruby:基于谓词的搜索记录 - 请提出更好的解决方案

时间:2016-07-13 09:53:10

标签: ruby

(我已经为下面的问题写了一个解决方案,但是想问一下是否有人可以建议一个更清洁的解决方案,更多的是在#34; Spirit" Ruby中。)

问题:我有一组(有序的)针,大海捞针中的(有序)元素集,以及带针和干草堆元素并产生真或假的谓词。任务是找到第一个针头,其中谓词为true,其中有一些haystack元素,然后返回haystack元素。我们对针头不感兴趣。针和草垛表示为阵列。

例如,如果

needles = [17,3,7,121]
haystack = [40,30,70]

,谓词是

def p(needle, hay)
  hay % needle == 0
end

结果应为30,因为对于针17,haystack中没有元素满足谓词,但对于针3,第二个元素(30)可以。

这是我的实施:

found = nil
needles.find do |n|
  found = haystack.find { |he| p(n,he) }
  break if found 
end

我觉得有点不自然的是,我基本上抛弃了外部find的结果,需要携带变量found,最终保存结果。我正在寻找一个更简洁的表达式,它直接将结果赋给found,即:

found = ...... 

有什么想法吗?

1 个答案:

答案 0 :(得分:1)

需要注意的重要一点是,它是您要查找的haystack元素,而不是needle。因此,此变量必须是最外层循环中的变量。

然后通过更加惯用来使用Enumerable#any?检查是否存在满足谓词的针,因为您实际上只关心true / false返回值。 / p>

最终结果是:

haystack.find do |he|
  needles.any? { |needle| p(needle, he) }
end

编辑:我稍微误解了这个问题,抱歉。如果我们订购针头,并找到第一个满足谓词“最高阶”针头的干草堆,那么我们就可以做到:

haystack
  .select { |he| needles.any? { |needle| p(needle, he) } }
  .min_by { |he| needles.index { |needle| p(needle, he) } }

或者作为替代(更有效)的解决方案,如何:

haystack.min_by do |he|
  needles.index { |needle| p(needle, he) } || Float::INFINITY  
end

如果Float::INFINITYneedles元素的条件匹配,则会使用haystack这个有趣的用法,在这种情况下index方法返回nil