我正在使用Ruby 2.4。假设我有一个字符串数组(这些字符串都是字符串组合的(是一个单词吗?)整数...
["1", "2", "5", "25", "5"]
如何编写一个函数,告诉我数组中的所有元素是否在数组中出现的次数不超过两次?例如,这个数组
["1", "3", "3", "55", "3", "2"]
将返回false
因为"3"
出现三次,但此数组
["20", "10", "20", "10"]
将返回true
,因为所有元素都不会超过两次。
答案 0 :(得分:6)
您可以像这样确定频率:
frequency = array.reduce(Hash.new(0)) do |counts, value|
counts[value] += 1
counts
end
# => { "1" => 1, "3" => 3, "55" => 1, "2" => 1 }
你可以检查它们中的任何一个是否出现过两次以上:
frequency.values.max > 2
如果你想很好地包装它,可以将它添加到Enumerable:
module Enumerable
def frequency
f = Hash.new(0)
each { |v| f[v] += 1 }
f
end
end
然后你的情况就像:
array.frequency.values.max > 2
注意:这是Facets的一部分。
答案 1 :(得分:6)
Enumerable#group_by将为此付出沉重的代价:
def no_element_present_more_than_twice?(a)
a.group_by(&:itself).none? do |_key, values|
values.count > 2
end
end
p no_element_present_more_than_twice?(["1", "3", "3", "55", "3", "2"])
# => false
p no_element_present_more_than_twice?(["20", "10", "20", "10"])
答案 2 :(得分:6)
试试这个
count = Hash.new(0)
array.none? { |each| (count[each] += 1) > 2 }
# => true or false
这是如何运作的?
Hash.new(0)
创建一个默认值为0
none?
检查所有元素的块并返回是否没有元素匹配count[each] += 1
会增加点数(无nil
个案,因为默认值为0
)这是一种最佳解决方案,因为一旦发现第一个违规元素,它就会中断。此处发布的所有其他解决方案要么扫描整个阵列,要么更复杂。
注意,如果您想知道哪些元素出现两次以上(例如打印错误消息),请使用find
或find_all
代替none?
。
答案 3 :(得分:6)
我已经把它作为你的所有选项的基准:)
keywords = ['adidas', 'thenextdoor', 'Uncaged']
links = soup.find_all('a',
class_='add_to_compare',
href=lambda href: all(keyword in href for keyword in keywords))
for link in links:
print(link["href"])
正如您所看到的,@ akuhn的答案比其他算法的表现要好得多,因为一旦找到匹配项就会提前退出。
注意:我编辑了答案以产生相同的结果,但没有编辑任何结果以进行优化。
以下是制作基准的脚本:
Running each test 1024 times. Test will take about 34 seconds.
_akuhn is faster than _vlasiak by 16x ± 1.0
_vlasiak is faster than _wayne by 3.5x ± 0.1
_wayne is faster than _cary by 10.0% ± 1.0%
_cary is faster than _oneneptune by 10.09% ± 1.0%
_oneneptune is similar to _coreyward
_coreyward is faster than _tadman by 10.0% ± 1.0%
_tadman is faster than _sagarpandya82 by 10.0% ± 1.0%
_sagarpandya82 is faster than _glykyo by 80.0% ± 1.0%
答案 4 :(得分:2)
这是另一种方法,使用方法Array#difference
:
def twice_at_most?(arr)
arr.difference(arr.uniq*2).empty?
end
其中Array#difference
的定义如下:
class Array
def difference(other)
h = other.each_with_object(Hash.new(0)) { |e,h| h[e] += 1 }
reject { |e| h[e] > 0 && h[e] -= 1 }
end
end
在找到Array#difference
的许多用途后,我将proposed that it be adopted作为核心方法。此链接中的文档说明了该方法的工作原理并提供了其使用示例。
试试吧。
twice_at_most? [1, 4, 2, 4, 1, 3, 4]
#=> false
这里
arr.uniq*2
#=> [1, 4, 2, 3, 1, 4, 2, 3]
arr.difference(arr.uniq*2)
#=> [4]
另一个例子:
twice_at_most? [1, 4, 2, 4, 1, 3, 5]
#=> true
答案 5 :(得分:1)
这是一种适合你的方法。
def lessThanThree(arr)
arr.each_with_object(Hash.new(0)) { |element,counts| counts[element] += 1 }.values.max < 3
end
基本上,获取数组,迭代创建哈希并计算每次出现,然后values方法只生成一个包含所有计数(值)的数组,然后max找到最高值。我们检查是否小于3,如果是,则返回true,否则返回false。您可以使用代码块替换true或false。
答案 6 :(得分:1)
为了避免大量的临时开销,只需sort
数组,然后将其拆分为类似元素的块。然后,您可以找到最长的块:
def max_count(arr)
arr.sort.slice_when { |a,b| a != b }.map(&:length).max.to_i
end
max_count(%w[ 1 3 3 55 3 2 ])
# => 3
max_count(%w[ 1 3 55 3 2 ])
# => 2
max_count([ ])
# => 0
答案 7 :(得分:1)
只是这里有趣的方法是使用each_cons
并使用Wayne Conrad在其答案中使用的none?
。
arr.sort_by(&:to_i).each_cons(3).none? { |a,b,c| a == b && b == c }
答案 8 :(得分:1)
在我看来,这可能是一个非常简单的解决方案:
def no_more_than_twice_occur?(array)
array.none? { |el| array.count(el) > 2 }
end
no_more_than_twice_occur?(["1", "3", "3", "55", "3", "2"]) # => false
no_more_than_twice_occur?(["20", "10", "20", "10"]) # => true
答案 9 :(得分:-1)
对于数组中的每个唯一项,计算该元素在数组中出现的次数。在这些值中,检查max是否<= 2。
def max_occurence_at_most_2?(array)
array.uniq.map{ |element| array.count(element) }.max <= 2
end
未针对速度进行优化。