Range modifications
Quite a bit of this is just transforming syntax back and forth. Raku already has Ranges and Sequences as first class objects, though the syntax is different.
Demonstrate the task required examples: adding and removing integers, as well as an example adding and removing ranges to / from the sequence, in both native Raku syntax and the "Stringy" syntax required by the task.
Demo with some extremely large values / ranges. Capable of working with infinite ranges by default.
Won't handle negative numbers as written, mostly due the need to work around the syntax requirements for output.
my @seq;
-> $op, $string { printf "%20s -> %s\n", $op, $string } for
'Start', to-string( @seq = canonicalize "" ),
'add 77', to-string( @seq .= &add(77) ),
'add 79', to-string( @seq .= &add(79) ),
'add 78', to-string( @seq .= &add(78) ),
'remove 77', to-string( @seq .= &remove(77) ),
'remove 78', to-string( @seq .= &remove(78) ),
'remove 79', to-string( @seq .= &remove(79) );
say '';
-> $op, $string { printf "%20s -> %s\n", $op, $string } for
'Start', to-string( @seq = canonicalize "1-3,5-5" ),
'add 1', to-string( @seq .= &add(1) ),
'remove 4', to-string( @seq .= &remove(4) ),
'add 7', to-string( @seq .= &add(7) ),
'add 8', to-string( @seq .= &add(8) ),
'add 6', to-string( @seq .= &add(6) ),
'remove 7', to-string( @seq .= &remove(7) );
say '';
-> $op, $string { printf "%20s -> %s\n", $op, $string } for
'Start', to-string( @seq = canonicalize "1-5,10-25,27-30" ),
'add 26', to-string( @seq .= &add(26) ),
'add 9', to-string( @seq .= &add(9) ),
'add 7', to-string( @seq .= &add(7) ),
'remove 26', to-string( @seq .= &remove(26) ),
'remove 9', to-string( @seq .= &remove(9) ),
'remove 7', to-string( @seq .= &remove(7) );
say '';
-> $op, $string { printf "%30s -> %s\n", $op, $string } for
'Start', to-string( @seq = canonicalize "6-57,160-251,2700-7000000" ),
'add "2502-2698"', to-string( @seq .= &add("2502-2698") ),
'add 41..69', to-string( @seq .= &add(41..69) ),
'remove 17..30', to-string( @seq .= &remove(17..30) ),
'remove 4391..6527', to-string( @seq .= &remove("4391-6527") ),
'add 2699', to-string( @seq .= &add(2699) ),
'add 76', to-string( @seq .= &add(76) ),
'add 78', to-string( @seq .= &add(78) ),
'remove "70-165"', to-string( @seq .= &remove("70-165") ),
'remove 16..31', to-string( @seq .= &remove(16..31) ),
'add 1.417e16 .. 3.2e21', to-string( @seq .= &add(1.417e16.Int .. 3.2e21.Int) ),
'remove "4001-Inf"', to-string( @seq .= &remove("4001-Inf") );
sub canonicalize (Str $ranges) { sort consolidate |sort parse-range $ranges }
sub parse-range (Str $_) { .comb(/\d+|'Inf'/).map: { +$^α .. +$^ω } }
sub to-string (@ranges) { qq|"{ @ranges».minmax».join('-').join(',') }"| }
multi add (@ranges, Int $i) { samewith @ranges, $i .. $i }
multi add (@ranges, Str $s) { samewith @ranges, |parse-range($s) }
multi add (@ranges, Range $r) { @ranges > 0 ?? (sort consolidate |sort |@ranges, $r) !! $r }
multi remove (@ranges, Int $i) { samewith @ranges, $i .. $i }
multi remove (@ranges, Str $s) { samewith @ranges, |parse-range($s) }
multi remove (@ranges, Range $r) {
gather for |@ranges -> $this {
if $r.min <= $this.min {
if $r.max >= $this.min and $r.max < $this.max {
take $r.max + 1 .. $this.max
}
elsif $r.max < $this.min {
take $this
}
}
else {
if $r.max >= $this.max and $r.min <= $this.max {
take $this.min .. $r.min - 1
}
elsif $r.max < $this.max and $r.min > $this.min {
take $this.min .. $r.min - 1;
take $r.max + 1 .. $this.max
}
else {
take $this
}
}
}
}
multi consolidate() { () }
multi consolidate($this is copy, **@those) {
sub infix:<∪> (Range $a, Range $b) { Range.new($a.min,max($a.max,$b.max)) }
sub infix:<∩> (Range $a, Range $b) { so $a.max >= $b.min }
my @ranges = sort gather {
for consolidate |@those -> $that {
next unless $that;
if $this ∩ $that { $this ∪= $that }
else { take $that }
}
take $this;
}
for reverse ^(@ranges - 1) {
if @ranges[$_].max == @ranges[$_ + 1].min - 1 {
@ranges[$_] = @ranges[$_].min .. @ranges[$_ + 1].max;
@ranges[$_ + 1]:delete
}
}
@ranges
}
Output:
Start -> ""
add 77 -> "77-77"
add 79 -> "77-77,79-79"
add 78 -> "77-79"
remove 77 -> "78-79"
remove 78 -> "79-79"
remove 79 -> ""
Start -> "1-3,5-5"
add 1 -> "1-3,5-5"
remove 4 -> "1-3,5-5"
add 7 -> "1-3,5-5,7-7"
add 8 -> "1-3,5-5,7-8"
add 6 -> "1-3,5-8"
remove 7 -> "1-3,5-6,8-8"
Start -> "1-5,10-25,27-30"
add 26 -> "1-5,10-30"
add 9 -> "1-5,9-30"
add 7 -> "1-5,7-7,9-30"
remove 26 -> "1-5,7-7,9-25,27-30"
remove 9 -> "1-5,7-7,10-25,27-30"
remove 7 -> "1-5,10-25,27-30"
Start -> "6-57,160-251,2700-7000000"
add "2502-2698" -> "6-57,160-251,2502-2698,2700-7000000"
add 41..69 -> "6-69,160-251,2502-2698,2700-7000000"
remove 17..30 -> "6-16,31-69,160-251,2502-2698,2700-7000000"
remove 4391..6527 -> "6-16,31-69,160-251,2502-2698,2700-4390,6528-7000000"
add 2699 -> "6-16,31-69,160-251,2502-4390,6528-7000000"
add 76 -> "6-16,31-69,76-76,160-251,2502-4390,6528-7000000"
add 78 -> "6-16,31-69,76-76,78-78,160-251,2502-4390,6528-7000000"
remove "70-165" -> "6-16,31-69,166-251,2502-4390,6528-7000000"
remove 16..31 -> "6-15,32-69,166-251,2502-4390,6528-7000000"
add 1.417e16 .. 3.2e21 -> "6-15,32-69,166-251,2502-4390,6528-7000000,14170000000000000-3200000000000000000000"
remove "4001-Inf" -> "6-15,32-69,166-251,2502-4000"
Last updated