【问题标题】:SockMerchant Challenge Ruby Array#count not counting?SockMerchant 挑战 Ruby 数组#count 不算数?
【发布时间】:2019-04-11 12:21:56
【问题描述】:

所以,我正在对 HackerHank 进行初学者挑战,而 ruby​​ 的一个奇怪行为让我大吃一惊。

挑战是:找出并计算数组中有多少对。 (袜子对)

这是我的代码。

n = 100
ar = %w(50 49 38 49 78 36 25 96 10 67 78 58 98 8 53 1 4 7 29 6 59 93 74 3 67 47 12 85 84 40 81 85 89 70 33 66 6 9 13 67 75 42 24 73 49 28 25 5 86 53 10 44 45 35 47 11 81 10 47 16 49 79 52 89 100 36 6 57 96 18 23 71 11 99 95 12 78 19 16 64 23 77 7 19 11 5 81 43 14 27 11 63 57 62 3 56 50 9 13 45)

def sockMerchant(n, ar)
counter = 0
ar.each do |item|
  if ar.count(item) >= 2
    counter += ar.count(item)/2
    ar.delete(item)
  end
end
counter
end

print sockMerchant(n, ar)

问题是,它算不上好。运行函数后,它的内部数组 ar 仍然有可数对,我通过再次运行它来证明它。

还有更多。如果对数组进行排序,它的行为会有所不同。

这对我来说没有意义。

您可以在此链接上检查行为

https://repl.it/repls/HuskyFrighteningNaturallanguage

【问题讨论】:

  • 什么是n? (您的代码中没有使用它。)根据我的经验,ar.size/2 - ar.uniq.size 应该提供一个近似值,因为匹配的袜子的数量似乎总是一个奇数。
  • Array.count 是直接在Array 类上调用的方法,不存在。 Array#count 正在讨论 Array 实例的实例方法。这可能看起来很学术,但这是一个巨大的差异。
  • 要考虑的另一件事是,在 Ruby 中,大写字母在语法中具有含义,并且是保留的或 CaseNameCONSTANT_NAME 情况。应该将此方法称为sock_merchant 以符合这些期望。

标签: arrays ruby sorting counting


【解决方案1】:

您在迭代集合时从集合中删除项目 - 预计会发生坏事。简而言之,如果您不想出现此类问题,请不要这样做,请参阅:

> arr = [1,2,1]
# => [1, 2, 1] 
> arr.each {|x| puts x; arr.delete(x) }
# 1
#  => [2]

我们在迭代中从未得到2

一个简单的解决方案,即您的代码的一个小变体,如下所示:

def sock_merchant(ar)
  ar.uniq.sum do |item|
    ar.count(item) / 2
  end
end

这基本上是找到所有独特的袜子,然后为每只袜子计数。

请注意,它的复杂度是n^2,因为对于数组的每个唯一元素n,您必须遍历整个数组才能找到所有等于n 的元素。

另一种方法,首先将所有袜子分组,然后检查每种类型的袜子数量:

ar.group_by(&:itself).sum { |k,v| v.size / 2 }

作为ar.group_by(&:itself)ar.group_by { |x| x.itself } 的缩写将遍历数组并创建如下所示的哈希:

{"50"=>["50", "50"], "49"=>["49", "49", "49", "49"], "38"=>["38"], ...}

通过调用sum,我们将对其进行迭代,将找到的元素的数量相加 (/2)。

【讨论】:

  • 这些答案非常完美。您能否详细说明单行解决方案?
  • 试图再解释一下group_by