使用Ruby比较数组中的两个项目

我遇到的问题是需要使用方法比较数组中的两个元素。 我发现使用嵌套循环的逻辑很简单,但这可能不是Ru​​by的好用。

对于前者 确定数组是否有任何一对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 } 

其中kv代表“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] ,你必须采取不同的方法。