使用Ruby比较数组中的两个项目
我遇到的问题是需要使用方法比较数组中的两个元素。 我发现使用嵌套循环的逻辑很简单,但这可能不是Ruby的好用。
对于前者 确定数组是否有任何一对2个等于0的数字:
def pairs(array) i = 0 while i < array.length y = i + 1 while y < array.length if array[i] + array[y] == 0 return true end y += 1 end i += 1 end return false end
或者,如果我想看看数组中的两个东西是否相同,我将使用相同的逻辑,除了set:if array [i] == to array [y] …
有人能为这样的问题提供更好的方法吗?
通常,您可以将英语规范直接翻译成Ruby。
在第一个问题中,您询问两个元素的任何组合是否增加为零。 当你想知道可枚举的任何元素是否为真时使用的方法是Enumerable#any?
。 如果要处理数组中元素的组合,可以使用Array#combination
方法。 对于求和,您可以使用Numeric#+
或Enumerable#inject
,如果您想知道数字是否为零,您可以使用Numeric#zero?
。
因此,您的第一个问题的可能实现将是:
ary.combination(2).any? {|pair| pair.inject(:+).zero? }
你的第二个问题可以通过以下方式回答:
ary.combination(2).any? {|a, b| a == b }
在这两种情况下,当然还有其他方法可以做到这一点。 例如,在第一种情况下,我们可以观察到两个数字总和为零的唯一方法是,如果一个是另一个的负数。
请注意,循环中通常可能出错的事情都不会发生在这里。 没有off-by-one错误,没有fencepost错误,没有错误的终止条件,没有迭代结束数组,只是因为没有循环。
如果您只想计算数组中元素的出现次数,可以使用Enumerable #count
a = [1,2,3,4,5,1,2,2] a.count(2) # => 3
现在,如果要查看数组中是否有重复条目,可以使用uniq
方法
def has_duplicates?(arr) arr.uniq.length == arr.length end
这是我对你的第一个问题的方法和另一个返回对的方法:
def pairs?(arr) arr.inject(false){|c, v| c || (arr.include?(-v) && v > 0)} end def get_pairs(arr) arr.collect{|val| [val, -val] if arr.include?(-val) && val > 0}.reject(&:nil?) end arr = [1, 8, -2, 12, -15, 5, 3] p pairs?(arr) p get_pairs(arr) arr = [1, 8, -2, 12, -15, 5, 3, 2, -3, 1] p pairs?(arr) p get_pairs(arr)
输出:
false [] true [[3, -3], [2, -2]]
但是,当有一对零时,它们不起作用。 您可以明确处理该案例,也可能有人可以提供更好的解决方案。
你会喜欢Ruby,部分原因是你通常不会使用索引来提取或设置数组的元素。
码
def pairs(arr) arr.map { |e| e < 0 ? -e : e }. group_by(&:itself). select { |_,v| v.size > 1 }. keys end
例子
pairs [1, 8, -2, 12, -15, 5, 3] #=> [] pairs [1, 8, -2, 12, -15, 5, 3, 2, -3, 1] #=> [1, 2, 3]
如果你想要第二个例子返回[[1, -1], [2, -2], [3, -3]]
(虽然我没有看到这一点),用以下方法替换方法的倒数第二行:
map { |k,_| [k, -k] }
说明
步骤:
arr = [1, 8, -2, 12, -15, 5, 3, 2, -3, 1]
是:
a = arr.map { |e| e < 0 ? -e : e } #=> [1, 8, 2, 12, 15, 5, 3, 2, 3, 1] b = a.group_by(&:itself) #=> {1=>[1, 1], 8=>[8], 2=>[2, 2], 12=>[12], 15=>[15], 5=>[5], 3=>[3, 3]}
我们在Ruby v2.2中获得了Object#本身 。 对于早期版本,请使用:
b = a.group_by { |e| e }
继续:
c = b.select { |_,v| v.size > 1 } #=> {1=>[1, 1], 2=>[2, 2], 3=>[3, 3]} c.keys #=> [1, 2, 3]
这条线:
select { |_,v| v.size > 1 }
可写:
select { |k,v| v.size > 1 }
其中k
和v
代表“key”和“value”,但由于k
不用于块计算,通常的做法是用局部变量_
替换k
(是的,它是变量 – 在IRB中尝试),主要是告知读者该参数未在块中使用。
如果arr = [1, 1, -1, -1, 2, -2]
[1,2]
arr = [1, 1, -1, -1, 2, -2]
,则返回[1,2]
。 如果你想要它返回[1,1,2]
,你必须采取不同的方法。