我尝试将范围(例如1-9
)的常见字符串描述解析为实际范围(例如1 .. 9
),但在包含两位数字时经常得到奇怪的结果。例如,1-10
会生成单个值1
而不是十个值列表,而11-20
会给我四个值(11 10 21 20
),其中一半不均匀在预期的数值范围内:
put get_range_for('1-9');
put get_range_for('1-10');
put get_range_for('11-20');
sub get_range_for ( $string ) {
my ($start, $stop) = $string.split('-');
my @values = ($start .. $stop).flat;
return @values;
}
打印:
1 2 3 4 5 6 7 8 9
1
11 10 21 20
而不是预期的:
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
(我在发布这个问题之前想到了这一点,所以我在下面回答。如果你想详细说明,请随意添加你自己的答案。)
答案 0 :(得分:9)
问题确实是.split
返回Str
而不是Int
,原始答案解决了这个问题。但是,我宁愿像这样实现我的“get_range_for”:
sub get_range_for($string) {
Range.new( |$string.split("-")>>.Int )
}
这将返回Range
个对象而不是Array
。但是对于迭代(这是你最有可能使用它),这不会有任何区别。此外,对于较大范围,“get_range_for”的其他实现可能会占用大量内存,因为它将Range
转化为Array
。这对于“3-10”来说并不重要,但它会用于“1-10000000”。
请注意,此实现使用>>.Int
对从.split
返回的所有值调用Int方法,然后将它们作为单独的参数单击|
到Range.new
。如果.split
返回1值(如果它不能拆分)或超过2个值(如果字符串中出现多个连字符),那么这也会爆炸。
答案 1 :(得分:7)
split
的结果是Str
,因此您不小心创建了一系列字符串而不是一系列整数。在创建范围之前,请尝试将$start
和$stop
转换为Int
:
put get_range_for('1-9');
put get_range_for('1-10');
put get_range_for('11-20');
sub get_range_for ( $string ) {
my ($start, $stop) = $string.split('-');
my @values = ($start.Int .. $stop.Int).flat; # Simply added .Int here
return @values;
}
给你你期望的东西:
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20