【问题标题】:Split number into equal parts or what's closest to that将数字分成相等的部分或最接近的部分
【发布时间】:2016-04-05 00:03:54
【问题描述】:

我有一个随机数,我想把它分成几个部分(加数),条件是一个部分不能超过 20,并且这些部分必须尽可能接近。

例如,如果我的随机数是 41,加数应该是 14、14、13。 如果随机数为 60,则加数应为 20、20、20。 如果随机数是 21 加数应该是 11 和 10 等等。

我的代码是用 Ruby (Rails) 编写的,所以我非常感谢能在 Ruby 中有效实现这一点的答案,尽管也欢迎使用伪代码或其他编程语言。

这是我为数组找到的,但我真的需要用数字来做这件事:“Splitting an array into equal parts in ruby

【问题讨论】:

  • 欢迎来到 SO。请阅读“How to Ask”,包括该页面中的链接。你要我们为你写代码?这不是 Stack Overflow 的用途。相反,你做研究,你尝试,然后,当你遇到问题时,你向我们展示你尝试了什么,我们帮助你解决它。 meta.stackoverflow.com/q/261592/128421 读起来很有用。
  • 你期望有多少个加数?
  • 那将是题外话:“要求我们推荐或查找书籍、工具、软件库、教程或其他非现场资源的问题对于 Stack Overflow 来说是题外话,因为它们往往吸引固执己见的答案和垃圾邮件。相反,describe the problem 以及迄今为止为解决它所做的工作。”目前,您看起来像是在查看单个页面。还有哪里?
  • @theTinMan 你知道我在你编辑之前看到了你的 cmets,对吧?我的朋友,你的态度有严重问题,我希望你有一天会好起来。同时,请看这个问题,它有你提到的类似问题,我认为这是你让世界变得更美好的机会:stackoverflow.com/questions/13585591/…
  • 您最后的评论非常不恰当。多年来,@theTinMan 在 SO 上为 Ruby 社区做出了巨大贡献,我记得拥有第三高的代表。他只是向您告知了 SO 政策,您的回应是告诉他他态度不好,以及他如何才能更有效率地度过他的时间。当您在 SO 上花费更多时间时,您会看到 tTM 留下了许多类似的 cmets,以努力提高发布到 SO 的问题的质量。没有理由仅仅因为这不是你会做的事情而粗鲁。

标签: ruby-on-rails ruby math


【解决方案1】:

你可以使用这个很酷的单线。它应该可以除以您想要的任意数量的部分:

def split_into n, p
    [n/p + 1] * (n%p) + [n/p] * (p - n%p)
end

print (split_into 32, 3) # => [11, 11, 10]

它基本上将数字分成相等的部分,并将剩余部分除以第一个部分(每个 1)。这以及您可以将数组相乘和相加的事实,如下所示:

[1] * 3     # => [1, 1, 1]
[1] + [2]   # => [1, 2]

编辑:考虑到每件应小于 20 件的规则,您可以按照@Cary Swoveland 的建议计算理想的件数:

p = (n / 20.0).ceil

【讨论】:

  • @CarySwoveland 你的问题是对的。虽然我相信这个答案非常接近。它只需要一个小添加,即在方法中移动'p'并将其设置为1。然后将其放入循环中p+=1直到n/p < 21
  • @CarySwoveland 这就是我们所说的答案对吧?我的循环split_into 1_000_000, 1) #=> [1000000] 不正确。由于 1000000/1 > 20,它会尝试 1000000/2,然后是 1000000/3,依此类推,直到达到返回 20 或更少的数字的值。在此之后,Sly 的代码就像一个魅力
  • 那么就需要这样做了。无需迭代:p = (n/20.0).ceil.
【解决方案2】:

代码

n 为要被除的给定数,m 为每个分量的最大值。

def doit(n,m)
  nbr_components = (n/(m.to_f)).ceil
  smaller, nbr_larger = n.divmod(nbr_components)
  { smaller=>nbr_components-nbr_larger, smaller+1=>nbr_larger }.
    delete_if { |_,v| v.zero? }
end

Fixnum#divmod 是一个经常被忽视的方法,有很多用途。

示例

(1..300).to_a.sample(15).sort.each { |n| puts "doit(#{n},20) = #{doit(n,20)}" }
doit(2,20)   = {2=>1}
doit(7,20)   = {7=>1}
doit(13,20)  = {13=>1}
doit(19,20)  = {19=>1}
doit(32,20)  = {16=>2}
doit(36,20)  = {18=>2}
doit(47,20)  = {15=>1, 16=>2}
doit(61,20)  = {15=>3, 16=>1}
doit(77,20)  = {19=>3, 20=>1}
doit(146,20) = {18=>6, 19=>2}
doit(149,20) = {18=>3, 19=>5}
doit(160,20) = {20=>8}
doit(199,20) = {19=>1, 20=>9}
doit(253,20) = {19=>7, 20=>6}
doit(275,20) = {19=>5, 20=>9}

doit(11_347_155, 20)
  #=> {19=>5, 20=>567353}
5*19 + 567353*20
  #=> 11347155

说明

假设:

n = 77
m = 20

步骤如下:

nbr_components = (n/(m.to_f)).ceil
  #=> (77/20.0).ceil
  #=> 3.85.ceil
  #=> 4 
smaller, nbr_larger = n.divmod(nbr_components)
  #=> 77.divmod(4) 
  #=> [19, 1] 
smaller
  #=> 19
nbr_larger
  #=> 1
h = { smaller=>nbr_components-nbr_larger, smaller+1=>nbr_larger }
  #=> {19=>3, 20=>1}
h.delete_if { |_,v| v.zero? }
  #=> {19=>3, 20=>1}

【讨论】:

    【解决方案3】:

    没有内置函数可以执行此操作。

    我可以为您写出解决方案,但通常您应该在 StackOverflow 问题中加入您自己的尝试。这种类型的问题似乎是学习 ruby​​ 语言基础知识的练习。如果您不确定从哪里开始,我建议您阅读 Ruby 教科书。

    def split_number_into_three(number) # i.e. number=32
      base = Array.new(3, (number / 3)) # i.e. base=[10,10,10]
      remainder = number % 3            # i.e. remainer=2
      return base if remainder.zero?
      while remainder > 0
        base.each_with_index do |num, idx|
          if remainder > 0
            base[idx] += 1
            remainder -= 1
          end
        end
      end
      base
    end
    

    运行此代码:

    irb(main):035:0> split_number_into_three(32)
    => [11, 11, 10]
    

    【讨论】:

    • 很棒,很棒的麦克斯
    • 谢谢。我确实实现了这个方法,效果很好。当然,很容易对其进行修改,将其称为 split_number_into_n 以控制我希望将我的号码拆分成的部分数量。仍然 SlySherZ 的回答似乎更接近我的要求,所以我赞成并接受这一点
    • mizurnix,这显然不可能,因为这种方法没有考虑最大允许值(即 20)。注意:split_into 1_000_000, 1) #=> [1000000].
    • @mizurnix 是的,我明白你为什么会选择“很酷的一个班轮”。他们不可能都是赢家!
    猜你喜欢
    • 2015-12-09
    • 2015-05-23
    • 1970-01-01
    • 2019-05-06
    • 1970-01-01
    • 2011-07-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多