【问题标题】:Compare sums of elements in an array: Ruby比较数组中元素的总和:Ruby
【发布时间】:2014-08-15 11:11:11
【问题描述】:

我需要检查数组中任意两个元素的总和是否等于给定的数字。这是我想出来的,但它似乎没有做比较

def sum_comparison(int_array, x)
  n = int_array.length
  (0..n).each do |i|
    (1..n).each do |j|
      if ((int_array[i].to_i + int_array[j].to_i) == x)
        return true
      else
        return false
      end
    end
  end
end

【问题讨论】:

  • 你有什么问题?
  • 我发布的代码似乎无法正常工作,我需要有人提示错误在哪里
  • sum_comparison 是如何使用的? int_array_length 是什么?
  • 我看不懂问题描述。您想查看二元素数组的总和是否等于某个值,或者任何两个元素之和,或者什么等?
  • 数组可以有任意数量的元素,不是必须的 2. 我需要检查数组中任意两个元素的总和是否等于某个数字(我将数字作为第二个参数传递给方法数字也可以。它说清楚了吗?

标签: ruby arrays sorting


【解决方案1】:

您的解决方案似乎过于复杂,并且受到 C 等低级过程语言的编程风格的强烈影响。一个明显的问题是您编写

n = int_array.length
(0..n).each do |i|
  # use int_array[i].to_i inside the loop
end

现在在each 循环中,您将获得数字i = 0, 1, 2, ..., n,例如对于int_array = [3,4,5],您将获得i = 0, 1, 2, 3。请注意,有四个元素,因为您从零开始计数(这称为一次错误关闭)。这最终将导致在n 的数组访问,这是数组末尾之外的一个。这将再次导致nil 返回,这可能是您使用to_i 将其转换回整数的原因,因为否则您将在进行加法时得到TypeError: nil can't be coerced into Fixnum。您可能想要的只是:

int_array.each do |i|
  # use i inside the loop
end

对于示例数组[3,4,5],这实际上会导致i = 3, 4, 5。要以更 Ruby 的方式获取数组的组合,例如可以使用 Array#combination。同样,您可以使用Array#any? 来检测任何组合是否满足指定条件:

def sum_comparison(array, x)
  array.combination(2).any? do |a, b|
    a + b == x
  end
end

【讨论】:

  • 有什么理由使用排列而不是组合?后者是前者的子集,足以考虑。
  • @sawa 你是对的,combination 更好,因为它会产生更少的结果,因此在不满足条件时会更快地终止。顺序无关紧要,因为整数加法是可交换的。
  • @p11y,谢谢它的帮助
【解决方案2】:

当您的函数比较第一个元素时,它会立即返回 false。迭代时只需要返回 true,如果没有找到则返回 false,以避免出现此问题:

def sum_comparison(int_array, x)
  n = int_array.size
  (0...n).each do |i|
    (1...n).each do |j|
      if (int_array[i].to_i + int_array[j].to_i) == x
        return true
      end
    end
  end
  false
end

为了简化这一点,您可以使用@p11y 建议的permutationcombinationany? 方法。要获得有根据的元素,您可以使用find or detect

def sum_comparison(a, x)
  a.combination(2).any? { |i, j| i + j == x }
end

a.combination(2).detect { |i, j| i + j == x }
# sum_comparison([1,2,3, 4], 6) => [2, 4]

【讨论】:

  • 对第一个(长)解决方案的小评论:您将始终遍历所有元素,找到匹配项时可以return true,只需在方法末尾写false。这使您可以提前终止。您使用detect 的建议非常有用。
【解决方案3】:

使用枚举器:

#!/usr/bin/env ruby

def sum_comparison(int_array, x)
  enum = int_array.to_enum
  loop do
    n = enum.next
    enum.peek_values.each do |m|
      return true if (n + m) == x
    end
  end
  false
end

puts sum_comparison([1, 2, 3, 4], 5)

输出:

true

【讨论】:

  • 为什么这样会更有效率?
  • @p11y 只是我的想法真的很抱歉。至少我觉得描绘起来更容易。
  • 我的意思是,虽然您的代码是正确的,但您只是使用较低级别的 API 来完成同样的事情。您的代码不会提前终止或其他什么。但是我有一个问题,因为它引入了更多的句法噪音。
  • @p11y 我明白了。这基本上是一个品味问题。实际上,如果Enumerator#peek_values 以编程方式优化元素指针不会被复制,那么表单应该比任何复制元素集的东西都要快。唯一的问题是我还没有时间看 Ruby 的代码。
  • 如果你刚开始是一名 C 语言的程序员,并且非常关心优化,你就会理解我的意思。那些开始使用解释性语言的人往往只关心可读性。
【解决方案4】:

问题

你的方法相当于:

def sum_comparison(int_array, x)
  return int_array[0].to_i + int_array[1].to_i == x
end

因此,

int_array = [1,2,4,16,32,7,5,7,8,22,28]
sum_comparison(int_array, 3) #=> true, just lucky!
sum_comparison(int_array, 6) #=> false, wrong!

替代方案

这是一个相对高效的实现,肯定比使用Enumerable#combination 高效得多。

代码

def sum_comparison(int_array, x)
  sorted = int_array.sort
  smallest = sorted.first
  sorted_stub = sorted.take_while { |e| e+smallest <= x }
  p "sorted_stub = #{sorted_stub}"
  return false if sorted_stub.size < 2
  loop do
    return false if sorted_stub.size < 2
    v = sorted_stub.shift
    found = sorted_stub.find { |e| v+e >= x }
    return true if found && v+found == x
  end
  false
end

示例

sum_comparison([7,16,4,12,-2,5,8], 3)
  # "sorted_stub = [-2, 4, 5]"
  #=> true
sum_comparison([7,16,4,12,-2,5,8], 7)
  # "sorted_stub = [-2, 4, 5, 7, 8]"
  #=> false
sum_comparison([7,16,4,22,18,12,2,41,5,8,17,31], 9)
  # "sorted_stub = [2, 4, 5, 7]"
  #=> true

备注

  • 包含p "sorted_stub = #{sorted_stub}" 行只是为了在示例中显示数组sorted_stub

  • 如果e+smallest &gt; x 用于sorted 中的任何元素fg,其中g &gt;= ef &lt; gf+g &gt;= e+smallest &gt; x。因此,sorted_stub.lastsorted 中需要考虑的最大值。

  • 对于给定值v,行found = sorted_stub.find { |e| v+e &gt;= x } 停止搜索第二个值e,一旦找到v+e = x,就会立即找到v+e &gt;= x。然后下一行确定是否找到了匹配项。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-09
    • 2016-03-25
    • 1970-01-01
    相关资源
    最近更新 更多