【问题标题】:Checking arrays and implementing bool methods检查数组并实现布尔方法
【发布时间】:2014-04-16 01:41:30
【问题描述】:

你有一个数组。如果数组中任意两个数字加到零,则返回true。有多少对并不重要——只要有一对加到零,就返回true。如果有一个零,它只能返回true,如果有多个。

我写了两个函数,一个用于检查每个函数,最后一个将两者结合起来,如果其中一个不满足,则返回false

def checkZero(array)
  zerocount = 0
  for j in 0..array.count
    if array[j] == 0
      zerocount += 1
    end
  end
  if zerocount > 1 #this part seems to not be working, not sure why
    return true
  else
    return false
  end
end

def checkNegative(array)
  for j in 0..array.count
    neg = -array[j] #set a negative value of the current value
    if array.include?(neg) #check to see whether the negative exists in the array
      return true
    else
      return false
    end
  end
end

def checkArray(array)
  if checkZero(array) == true or checkNegative(array) == true
    return true
  else
    return false
  end
end

然后运行类似

array = [1,2,3,4,0,1,-1]
checkArray(array)

到目前为止,Ruby 没有返回任何内容。我只是得到一个空白。我感觉我的return 不对。

【问题讨论】:

  • 一方面,不要在 Ruby 中使用 for。只需使用eachfor 字面意思就是调用each,所以它是单一的间接方式。此外,在checkZerocheckArray 中,您可以只将最后一条语句作为条件语句,无需if。此外,带下划线的方法名称更传统(例如check_array 而不是checkArray)。最后,请注意and/or is not the same as &&/|| in Ruby;当布尔逻辑是意图时,只能使用后者。
  • 哦,我无法重现您的问题,checkArray([1,2,3,4,0,1,-1]) 返回true 就好了。
  • @AndrewMarshall 感谢您的提示。将阅读 and/or 和 && || 之间的区别。

标签: ruby arrays boolean


【解决方案1】:

问题可能是你没有输出结果。

array = [1,2,3,4,0,1,-1]
puts checkArray(array)

如果性能 (O(n^2)) 不是一个大问题,checkArray 方法可以写成如下:

def check_array(array)
  array.combination(2).any?{|p| p.reduce(:+) == 0}
end

更高效的(O(n log n))解决方案是:

def check_array(array)
  array.sort! # `array = array.sort` if you need the original array unchanged
  i, j = 0, array.size - 1
  while i < j
    sum = array[i] + array[j]
    if sum > 0
      j -= 1
    elsif sum < 0
      i += 1
    else
      return true
    end
  end
  return false
end

【讨论】:

  • +1 因为可能是缺少的puts 让 OP 感到困惑。
  • 是的,我错过了 put,但我确实从每个人那里得到了很多很棒的代码建议。选择这个确实解决了我的问题,有效的算法解决方案也很棒。谢谢
  • @cheenbabes 你也可以投票给其他有用的答案,有一些很好的答案。
  • @MarkThomas 我试图为您的评论和安德鲁的评论这样做,但它说我没有足够的声誉。我会投票给他们所有人,因为他们都以不同的方式帮助了我,远远超出了拼图的范围。
【解决方案2】:

这里有一些相对有效的方法来检查任何两个值是否总和为零:

解决方案 #1

def checkit(a)
  return true if a.count(&:zero?) > 1
  b = a.uniq.map(&:abs)
  b.uniq.size < b.size
end

解决方案 #2

def checkit(a)
  return true if a.sort_by(&:abs).each_cons(2).find { |x,y| x == -y }
  false
end

解决方案 #3

def checkit(a)
  return true if a.count(&:zero?) > 1
  pos, non_pos = a.group_by { |n| n > 0 }.values
  (pos & non_pos.map { |n| -n }).any?
end

解决方案 #4

require 'set'

def checkit(a)
  a.each_with_object(Set.new) do |n,s|
    return true if s.include?(-n)
    s << n
  end
  false
end        

示例

checkit([1, 3, 4, 2, 2,-3,-5,-7, 0, 0]) #=> true
checkit([1, 3, 4, 2, 2,-3,-5,-7, 0])    #=> true 
checkit([1, 3, 4, 2,-3, 2,-3,-5,-7, 0]) #=> true
checkit([1, 3, 4, 2, 2,-5,-7, 0])       #=> false

说明

以下都是指数组:

a = [1,3,4,2,2,-3,-5,-7,0]

#1

零有点问题,所以让我们先看看是否有多个,在这种情况下我们就完成了。因为a.count(&amp;:zero?) #=&gt; 1a.count(&amp;:zero?) &gt; 1 #=&gt; false,所以

return true if a.count(&:zero?) > 1

不会导致我们返回。接下来,我们删除所有重复项:

a.uniq                #=> [1, 3, 4, 2, -3, -5, -7, 0]

然后将所有数字转换为它们的绝对值:

b = a.uniq,map(&:abs) #=> [1, 3, 4, 2,  3,  5,  7, 0]

最后查看c 是否包含任何重复,这意味着原始数组包含至少两个符号相反的非零数字:

c.uniq.size < c.size  #=> true

#2

b = a.sort_by(&:abs)
  #=> [0, 1, 2, 2, 3, -3, 4, -5, -7]

c = b.each_cons(2)
  #=> #<Enumerator: [0, 1, 2, 2, 3, -3, 4, -5, -7]:each_cons(2)>

查看枚举器的内容:

c.to_a
  #=> [[0, 1], [1, 2], [2, 2], [2, 3], [3, -3], [-3, 4], [4, -5], [-5, -7]]

c.find { |x,y| x == -y }
  #=> [3, -3]

所以返回 true。

#3

return true if a.count(&:zero?) > 1
  #=> return true if 1 > 1

h = a.group_by { |n| n > 0 }
  #=> {true=>[1, 3, 4, 2, 2], false=>[-3, -5, -7, 0]} 
b = h.values 
  #=> [[1, 3, 4, 2, 2], [-3, -5, -7, 0]] 
pos, non_pos = b
pos
  #=> [1, 3, 4, 2, 2]
non_pos
  #=> [-3, -5, -7, 0]
c = non_pos.map { |n| -n }
  #=> [3, 5, 7, 0] 
d = pos & c
  #=> [3] 
d.any?
  #=> true 

#4

require 'set'

enum = a.each_with_object(Set.new)
  #=> #<Enumerator: [1, 3, 4, 2, 2, -3, -5, -7, 0]:each_with_object(#<Set: {}>)>
enum.to_a
  #=> [[1, #<Set: {}>],
  #    [3, #<Set: {}>],
  #    ...
  #    [0, #<Set: {}>]]

值传入block,赋值给block变量,block被执行,如下:

n, s = enum.next
  #=> [1, #<Set: {}>] 
s.include?(-n)
  #=> #<Set: {}>.include?(-1)
  #=> false
s << n
  #=> #<Set: {1}>

n, s = enum.next
  #=> [3, #<Set: {1}>] 
s.include?(-3)
  #=> false 
s << n
  #=> #<Set: {1, 3}> 

...

n, s = enum.next
  #=> [2, #<Set: {1, 3, 4, 2}>] 
s.include?(-n)
  #=> false 
s << n
  #=> #<Set: {1, 3, 4, 2}> # no change

n, s = enum.next
  #=> [-3, #<Set: {1, 3, 4, 2}>] 
s.include?(-n)
  #=> true 

导致true 被返回。

【讨论】:

  • [1,2,2,3] 呢?
  • 呼应@MarkThomas,我认为您必须将正面和负面分开。更接近您的原始答案,尽管这也不完全正确。
  • 谢谢,我会把原来的贴回去!
  • @CarySwoveland 它仍然说[1, 2, 2, 3] 是真的,但它更接近于工作。不过,我认为拆分的棘手情况是[0, 0]
  • @CarySwoveland 这很接近:a.partition { |x| x &lt; 0 }.map { |xs| xs.map(&amp;:abs).sort }.reduce(:zip).any?,但我怀疑它在[0, 0] 上失败了,因为它们最终在同一个分区中。
【解决方案3】:

我无法重现您的代码的任何问题,但是您可以使用combination 非常简洁地表达解决方案以获取所有可能的对,然后将每对与reduce 相加,最后检查是否有zero?

[1,2,3,4,0,1,-1].combination(2).map { |pair| pair.reduce(:+) }.any?(&:zero?)

【讨论】:

  • 感谢您提供适当方法的链接并展示简洁的解决方案
【解决方案4】:

这有点像code review。让我们从第一种方法开始:

def checkZero(array)

Ruby 命名约定是snake_case 而不是camelCase。这应该是def check_zero(array)

现在循环:

  zerocount = 0
  for j in 0..array.count
    if array[j] == 0
      zerocount += 1
    end
  end

正如@AndrewMarshall 所说,for 不是惯用的。 each 更可取。然而,由于ArrayEnumerable 上的所有可用方法(包含在Array 中),在ruby 中几乎不需要在循环之前初始化变量。我强烈建议将这些方法记入内存。以上可以写成

array.any? {|number| number.zero?}

或等效

array.any?(&:zero?)

现在,这部分:

  if zerocount > 1 #this part seems to not be working, not sure why
    return true
  else
    return false
  end
end

只要你有模式

if (expr that returns true or false)
  return true
else
  return false
end

可以简化为简单的return (expr that returns true or false)。如果 return 是方法的最后一条语句,您甚至可以省略它。

把它们放在一起:

def check_zero(array)
  array.any?(&:zero?)
end

def check_zero_sum(array)
  array.combination(2).any?{|a,b| a + b == 0}
end

def check_array(array)
  check_zero(array) || check_zero_sum(array)
end

(注意我借用了 AndrewMarshall 的 check_zero_sum 代码,我认为这很容易理解,但 @CarySwoveland 的答案会更快)

编辑

我错过了 check_zero 甚至没有必要的事实,因为您至少需要一对,在这种情况下,您只需要 check_zero_sum

def check_array(array)
  array.combination(2).any?{|a,b| a + b == 0}
end

【讨论】:

  • check_zero 应该返回 true 当且仅当有多个零时。现在,即使只有一个,它也会返回 true。也许过滤然后检查大小?
  • 感谢您指出这一点。我错过了那个细节!那时甚至不需要 Check_zero。
  • @MarkThomas 谢谢!这对清理我的代码和学习很有帮助。是否所有以? 结尾的方法都返回布尔值?
  • @user2887161 以? 结尾的方法称为谓词方法,虽然它们不需要完全返回true/false,但您应该只解释它们的结果作为真/假。
  • @cheenbabes 他们按照惯例行事。从技术上讲,“?”只是方法名称末尾的有效字符。
猜你喜欢
  • 2021-09-16
  • 2020-07-08
  • 1970-01-01
  • 2016-01-11
  • 2015-05-25
  • 2020-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多