-
-
Save pragdave/570406 to your computer and use it in GitHub Desktop.
# encoding: utf-8 | |
input = [ 1, 2, 3, 4, 5, 8, 9, 11, 12, 13, 15 ] | |
# Need to box the value to make it mutable | |
State = Struct.new(:last_value) | |
# divide the input into runs of consecutive numbers | |
s = input.slice_before(State.new(input.first)) do |value, state| | |
(_, state.last_value = value != state.last_value.succ, value)[0] | |
end | |
# replace runs of 3 or more with first–last | |
p s.map {|runs| runs.size < 3 ? runs : "#{runs.first}–#{runs.last}"} | |
.flatten | |
.join(', ') # => 1–5, 8, 9, 11–13, 15 |
BTW: what is the "_" for?
_
is like any other Ruby variable (e.g. a = 1
). I see (and use) it when the variable doesn't matter but needs to be assigned somewhere, typically in loops or iterators.
Thanks for putting this out there, Dave! A great use of #slice_before.
I refactored the code a bit as I was working through it and published it as a fork.
thanks edavis10. I'm a ruby nuby
why was _ = value != state.last_value.succ
needed?
that's the return value of the block, which is set to true whenever it detects a break in the sequence of input values
wow, i have a lot to learn. (yippee!)
too bad you couldn't throw in some c-style bit twiddling .
looking at this a couple months later and after reading PragProg's awesome MetaProgramming with Ruby book (even tho there is not really anything specific in the book that applies here), I can make better sense out of the original source now. Progress.
Yeah: I've changed it. I just though the parallel assignment trick as a way of saying the old value was neat.
Sigh...