Ruby将数字拆分为1或一半

Ruby将数字拆分为1或一半,ruby,Ruby,我喜欢把分数分成n个位置的数组 假设我的分数是11,数组大小是12。 然后我想用一些数组来填充,例如11个1或10个1和2个半(0.5)。最后应该加起来是11 那么可能的分数是: size=12 可能的分数=(0..size)。步骤(0.5)。到 我可以创建12个位置的数组: scores=Array.new(大小){0} 我可以从以下可能的值中选择一个随机值: [0,0.5,1]。示例 如果可能的话,我正在寻找一种有效的方法来检索随机数组,而不需要很多状态变量。我已经在while循环中尝

我喜欢把分数分成n个位置的数组

假设我的分数是11,数组大小是12。 然后我想用一些数组来填充,例如11个1或10个1和2个半(0.5)。最后应该加起来是11

那么可能的分数是:

size=12
可能的分数=(0..size)。步骤(0.5)。到
我可以创建12个位置的数组:

scores=Array.new(大小){0}
我可以从以下可能的值中选择一个随机值:

[0,0.5,1]。示例
如果可能的话,我正在寻找一种有效的方法来检索随机数组,而不需要很多状态变量。我已经在while循环中尝试过这样做:

而分数<0
并使用随机值减少分数值,并跟踪设置的数组位置。但它变成了一段相当混乱的代码

有什么办法解决这个问题吗?谢谢

编辑:


对于这个例子,我想要一个总数为11的数组。那么你们中的任何一个

[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0] 

[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.5, 0.5] 

[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1] 

或者不管是什么组合,总共11个。

如果我明白了这一点,一个可能的选择是(暴力)

size=12
总和=11
tmp=Array.new(12){1}
环道
如果tmp.sum[0.5,0.5,1,1,1,1,1,1,1,1,1,1]
tmp.sum#=>11.0

Ruby提供了您所需的一切,无需编写任何算法代码。你的朋友在吗

[0, 0.5, 1].
  repeated_combination(12).    # 91 unique variant
  to_a.                        # unfortunately it cannot be lazy
  shuffle.                     # to randomize array outcome
  detect { |a| a.sum == 11 }.
  shuffle                      # to randomize numbers inside array
#⇒ [0.5, 0.5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]


旁注:使用可以避免两次洗牌(生成的数组和生成的数组),但这会大大增加内存负载和执行时间。

参数和变量

鉴于:

  • tot
    ,所需总数,为
    0.5的整数或奇数倍;及
  • size
    0
    0.5
    1
    的总数是总的
    tot
    ,要求
    size>=tot

我们定义了三个变量:

  • n0
    等于零的数目
  • n0pt5_对
    等于
    0.5
    的对数;及
  • n1
    等于一个数
案例1:
tot
是一个整数

我们要求:

0 <= n0pt5_pairs <= [tot, size-tot].min
因此,我们可以随机选择一个三元组
[n0,2*n0pt5_对,n1]
,如下所示:

def random_combo(size, tot)
  n0pt5_pairs = rand(1+[tot, size-tot].min)
  [size-tot-n0pt5_pairs, 2*n0pt5_pairs, tot-n0pt5_pairs]
end
例如:

arr = random_combo(17, 11)
  #=> [3, 6, 8]
这用于生成数组

arr1 = [*[0]*arr[0], *[0.5]*arr[1], *[1]*arr[2]]
  #=> [0, 0, 0, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 1, 1, 1, 1, 1, 1, 1, 1] 
我们洗牌:

arr1.shuffle
  #=> [1, 0, 0.5, 1, 0.5, 0, 1, 1, 0, 1, 1, 1, 0.5, 0.5, 1, 0.5, 0.5]
注意
arr1.size#=>17
arr.sum#=>11

情况2:
tot
是0.5的倍数

如果

如果
n
是一个整数,则
0
0.5
1
的每个组合将至少有一个
0.5
。因此,我们可以计算
0
1
的数量,以及超过1的
0.5
的数量。为此,我们只需将
tot
减少
0.5
(使其等于一个整数)并将
size
减少1,使用
generate\u for_integer
解决该问题,然后对于该方法返回的每个三元素数组,将
0.5
的数量增加1

def generate(size, tot)
  return nil if size.zero?
  is_int = (tot == tot.floor)
  tot = tot.floor
  size -= 1 unless is_int 
  n0pt5_pairs = rand(1+[tot, size-tot].min)
  [*[0]*(size-tot-n0pt5_pairs), *[0.5]*(2*n0pt5_pairs + (is_int ? 0 : 1)),
   *[1]*(tot-n0pt5_pairs)].
  shuffle
end


我喜欢Cary Swoveland的答案,但事实上,这可以在不产生一系列解决方案的情况下实现

让我们考虑几个例子。

给定size=6和score=3,在不进行混洗的情况下,这些是可能的输出(出于显而易见的原因,在左侧编号):

i 1/2 0
0│ 1 1 1 0 0 0    3     0      3
1.│ 1 1 ½ ½ 0 0    2     2      2
2.│ 1 ½ ½ ½ ½ 0    1     4      1
3.│ ½ ½ ½ ½ ½ ½    0     6      0
给定尺寸=6,分数=3.5:

i 1/2 0
0│ 1 1 1 ½ 0 0    3     1      2
1.│ 1 1 ½ ½ ½ 0    2     3      1
2.│ 1 ½ ½ ½ ½ ½    1     5      0
给定尺寸=11,分数=4.5:

i 1/2 0
0│ 1 1 1 1 ½ 0 0 0 0 0 0    4     1      6
1.│ 1 1 1 ½ ½ ½ 0 0 0 0 0    3     3      5
2.│ 1 1 ½ ½ ½ ½ ½ 0 0 0 0    2     5      4
3.│ 1 ½ ½ ½ ½ ½ ½ ½ 0 0 0    1     7      3
4.│ ½ ½ ½ ½ ½ ½ ½ ½ ½ 0 0    0     9      2
给定尺寸=12,分数=11:

i 1/2 0
0│ 1 1 1 1 1 1 1 1 1 1 1 0    11     0      1
1.│ 1 1 1 1 1 1 1 1 1 1 ½ ½    10     2      0
你能看到图案吗?在抓挠下巴之后,我们发现了以下事实:


  • 可能输出的数量不清楚您要做什么,也不清楚您为什么要做。你想解决什么问题?为什么不能简单地用分数填充数组,后跟一堆零?(例如,分数11,数组大小4:
    [11,0,0,0]
    )您是否试图使每个数字尽可能与其他数字相似?如果是这样的话,为什么不使用
    [11/4,11/4,11/4,11/4]
    ?我想要一个数组,它可以将这个[1,1,1,1,1,1,1,1,1,1,1]或[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0.5]加起来。它只能有值0、0.5或1。我需要它来生成测试数据。如果我运行你的方法
    random_scores(12,11)
    ,它会抛出一个错误,并且它不会一直返回一个大小为12的数组,这与我想要的非常接近,但我有一些不会引发异常的东西。我想要一个生成随机数组的东西,我之前没有提到过。抱歉。也许在最后添加
    shuffle
    。确实,shuffle可以做到这一点,谢谢。我有一个可行的解决方案,看看我的问题。我不知道它是否可以改进,但它确实有效。这正是我所追求的完美答案。两次洗牌都需要进行组合
    arr1.shuffle
      #=> [1, 0, 0.5, 1, 0.5, 0, 1, 1, 0, 1, 1, 1, 0.5, 0.5, 1, 0.5, 0.5]
    
    tot = n + 0.5
    
    def generate(size, tot)
      return nil if size.zero?
      is_int = (tot == tot.floor)
      tot = tot.floor
      size -= 1 unless is_int 
      n0pt5_pairs = rand(1+[tot, size-tot].min)
      [*[0]*(size-tot-n0pt5_pairs), *[0.5]*(2*n0pt5_pairs + (is_int ? 0 : 1)),
       *[1]*(tot-n0pt5_pairs)].
      shuffle
    end
    
    ge = generate(17, 10)
      #=> [0, 1, 0, 1, 0.5, 0.5, 0, 0.5, 0.5, 1, 1, 1, 1, 0.5, 0.5, 0.5, 0.5] 
    ge.size #=> 17 
    ge.sum  #=> 10.0 
    
    go = generate(17, 10.5)
      #=> [0.5, 0.5, 0.5, 1, 0, 0.5, 0.5, 1, 1, 0.5, 1, 1, 0.5, 1, 0.5, 0.5, 0] 
    go.size #=> 17 
    go.sum  #=> 10.5