如何将范围分成N部分
Posted
技术标签:
【中文标题】如何将范围分成N部分【英文标题】:How to split a range into N parts 【发布时间】:2016-09-27 15:13:50 【问题描述】:我想知道如何在 ruby 中将一个范围拆分为 N 个部分,同时将它们添加到一个散列中,并为每个生成的范围生成一个从零开始的值。
例如:
range = 1..60
p split(range, 4)
#=> 1..15 => 0, 16..30 => 1, 31..45 => 2, 46..60 => 3
我已经阅读了How to return a part of an array in Ruby? 以了解如何将范围切片为数组,以及其他一些有关如何将切片转换回范围的内容,但我似乎无法将所有部分拼凑在一起以创建我想要的方法。
感谢您的帮助
【问题讨论】:
有人刚刚对我的回答投了赞成票,所以我过来看看问题是什么。我看到您从未选择过答案。如果您发现任何答案有帮助,请考虑选择您喜欢的答案。哎呀,我看到只有一个。 【参考方案1】:range = 1..60
range.each_slice(range.last/4).with_index.with_object() |(a,i),h|
h[a.first..a.last]=i
#=> 1..15=>0, 16..30=>1, 31..45=>2, 46..60=>3
步骤如下:
enum0 = range.each_slice(range.last/4)
#=> range.each_slice(60/4)
# #<Enumerator: 1..60:each_slice(15)>
您可以将此枚举器转换为数组以查看它将生成并传递给each_with_index
的 (4) 个元素:
enum0.to_a
#=> [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
# [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30],
# [31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45],
# [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60]]
enum1 = enum0.with_index
#=> #<Enumerator: #<Enumerator: 1..60:each_slice(15)>:with_index>
enum1.to_a
#=> [[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], 0],
# [[16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30], 1],
# [[31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45], 2],
# [[46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60], 3]]
enum2 = enum1.with_object()
#=> #<Enumerator: #<Enumerator: #<Enumerator: 1..60:each_slice(15)>
# :with_index>:with_object()>
enum2.to_a
#=> [[[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], 0], ],
# [[[16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30], 1], ],
# [[[31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45], 2], ],
# [[[46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60], 3], ]]
仔细检查enum1
和enum2
的计算返回值。您可能想将它们视为“复合”枚举器。 enum2
的四个数组的第二个和最后一个元素是由块变量h
表示的空哈希。该哈希将在后续计算中构建。
enum2.each |(a,i),h| h[a.first..a.last]=i
#=> 1..15=>0, 16..30=>1, 31..45=>2, 46..60=>3
each
传递给块的enum2
的第一个元素(在执行enum.each...
之前)是
arr = enum2.next
#=>[[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], 0], ]
使用并行赋值(有时称为多重赋值)将块变量赋值给arr
的元素
(a,i),h = arr
#=> [[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], 0], ]
a #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
i #=> 0
h #=>
因此块计算是
h[a.first..a.last]=i
#=> h[1..15] = 0
现在
h #=> 1..15=>0
enum2
生成的其他 3 个元素中的每一个的计算都类似。
表达式
enum2.each |(a,i),h| h[(a.first..a.last)]=i
也可以写成
enum2.each |((f,*_,l),i),h| h[(f..l)]=i
【讨论】:
或.each_slice(15).map.with_index |d, i| (d.first..d.last) => i
可能更具可读性
@llya,需要一个散列,而不是散列数组,每个散列都有一个键值对。但是,您通过范围的建议是一个很好的建议。我会将其纳入我的答案中。
感谢您的回答!不幸的是,在我的机器ruby 2.2.3p173 (2015-08-18 revision 51636) [x64-mingw32]
上,您的代码返回[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]=>0, [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]=>1, [31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45]=>2, [46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60]=>3
而不是1..15=>0, 16..30=>1, 31..45=>2, 46..60=>3
,在某处有轻微的疏忽吗?如果不是,我如何检测单个整数是否落在键范围之间并返回其值。再次感谢。
继续:在我使用 hash.detect |k,v| k === 4.last
返回 4 所在范围的值之前。这将不再起作用,因为哈希的类型是array=>integer
而不是range=>integer
。有没有其他方法可以解决这部分问题?编辑:hash.detect |k,v| k.include?(4).last
现在可以使用。再次感谢。
兰迪,很抱歉给您带来不便。我回滚到我原来的答案,我相信这是正确的。我做了一个我认为会简化的更改,但没有彻底测试它以发现它是错误的。我将添加解释。以上是关于如何将范围分成N部分的主要内容,如果未能解决你的问题,请参考以下文章