Range modifications: Difference between revisions

(→‎{{header|Phix}}: merged action() into main, split() just the once rather than on every op.)
Line 204:
remove 7 => 1-5,10-25,27-30
</pre>
 
=={{header|Julia}}==
In this implementation the comma is used to separate only two consecutive numbers, so "1-3, 5, 6, 8-10" not "1-3, 5-6, 8-10". This could be changed easily by a minor alteration in the string() function.
<lang julia>import Base.string, Base.parse, Base.print
 
const RangeSequence = Array{UnitRange, 1}
 
function combine!(seq::RangeSequence, r2)
if isempty(seq)
push!(seq, r2)
else
r1 = seq[end]
if r1.start > r2.start
r1, r2 = r2, r1
end
if r2.stop > r1.stop
if r2.start <= r1.stop + 1
seq[end] = r1.start:r2.stop
else
push!(seq, r2)
end
end
end
return seq
end
 
function parse(::Type{RangeSequence}, s)
seq = UnitRange[]
entries = split(s, r"\s*,\s*")
for e in entries
startstop = split(e, r"\:|\-")
if length(startstop) == 2
start = tryparse(Int, startstop[1])
stop = tryparse(Int, startstop[2])
if start != nothing && stop != nothing
combine!(seq, start:stop)
end
elseif (n = tryparse(Int, startstop[1])) != nothing
combine!(seq, n:n)
end
end
return seq
end
 
function insertinteger!(seq, n::Integer)
isempty(seq) && return push!(seq, n:n)
pos = findlast(x -> x.start <= n, seq)
if pos == nothing
if seq[1].start - n > 1
pushfirst!(seq, n:n)
else
r = popfirst!(seq)
pushfirst!(seq, UnitRange(n:r.stop))
end
else
newseq = vcat(combine!(seq[1:pos], n:n), seq[pos+1:end])
empty!(seq)
append!(seq, newseq)
end
return seq
end
 
reduce(rangeseq) = begin seq = UnitRange[]; for r in rangeseq combine!(seq, r) end; seq end
 
function removeinteger!(seq, n::Integer)
pos = findlast(x -> x.start <= n, seq)
if pos != nothing
r1, r2 = seq[pos].start, seq[pos].stop
if r1 == r2 == n
deleteat!(seq, pos:pos)
elseif r2 == n
seq[pos] = r1:r2-1
elseif r1 == n
seq[pos] = r1+1:r2
elseif r1 < n < r2
seq[pos] = n+1:r2
insert!(seq, pos, r1:n-1)
end
end
return seq
end
 
function string(r::UnitRange)
r1, r2 = r.start, r.stop
return r1 == r2 ? "$r1" : abs(r1 - r2) > 1 ? "$r1-$r2" : "$r1, $r2"
end
 
print(io::IO, seq::RangeSequence) = print(io, join(map(string, reduce(seq)), ", "))
 
 
const seq = parse(RangeSequence, "")
println("Start: \"\"")
insertinteger!(seq, 77)
println(" added 77 => ", seq)
insertinteger!(seq, 79)
println(" added 79 => ", seq)
insertinteger!(seq, 78)
println(" added 78 => ", seq)
removeinteger!(seq, 77)
println(" removed 77 => ", seq)
removeinteger!(seq, 78)
println(" removed 78 => ", seq)
removeinteger!(seq, 79)
println(" removed 79 => ", seq, "\n")
 
const seq2 = parse(RangeSequence, "1-3, 5-5")
println("Start: $seq2")
insertinteger!(seq2, 1)
println(" added 1 => ", seq2)
removeinteger!(seq2, 4)
println(" removed 4 => ", seq2)
insertinteger!(seq2, 7)
println(" added 7 => ", seq2)
insertinteger!(seq2, 8)
println(" added 8 => ", seq2)
insertinteger!(seq2, 6)
println(" added 6 => ", seq2)
removeinteger!(seq2, 7)
println(" removed 7 => ", seq2, "\n")
 
const seq3 = parse(RangeSequence, "1-5, 10-25, 27-30")
println("Start: $seq3")
insertinteger!(seq3, 26)
println(" added 26 => ", seq3)
insertinteger!(seq3, 9)
println(" added 9 => ", seq3)
insertinteger!(seq3, 7)
println(" added 7 => ", seq3)
removeinteger!(seq3, 26)
println(" removed 26 => ", seq3)
removeinteger!(seq3, 9)
println(" removed 9 => ", seq3)
removeinteger!(seq3, 7)
println(" removed 7 => ", seq3)
 
</lang{{out}}
<pre>
Start: ""
added 77 => 77
added 79 => 77, 79
added 78 => 77-79
removed 77 => 78, 79
removed 78 => 79
removed 79 =>
 
Start: 1-3, 5
added 1 => 1-3, 5
removed 4 => 1-3, 5
added 7 => 1-3, 5, 7
added 8 => 1-3, 5, 7, 8
added 6 => 1-3, 5-8
removed 7 => 1-3, 5, 6, 8
 
Start: 1-5, 10-25, 27-30
added 26 => 1-5, 10-30
added 9 => 1-5, 9-30
added 7 => 1-5, 7, 9-30
removed 26 => 1-5, 7, 9-25, 27-30
removed 9 => 1-5, 7, 10-25, 27-30
removed 7 => 1-5, 10-25, 27-30
</pre>
 
 
=={{header|Phix}}==
4,102

edits