Challenge
Compactify a long list of numbers by replacing consecutive runs with ranges.
Example
Input
1, 2, 3, 4, 7, 8, 10, 12, 13, 14, 15
The input is guaranteed to be in ascending order and will not contain duplicates.
Output
1 - 4, 7, 8, 10, 12 - 15
Note that ranges of two numbers should be left as is. (7, 8
; not 7 - 8
)
Rules
You can accept a sorted list of integers (or equivalent datatype) as a method parameter, from the commandline, or from standard in. (pick whichever option results in shorter code)
You can output a list of strings by printing them, or by returning either a single string or set of strings.
Reference Implementation
(C#)
IEnumerable<string> Sample(IList<int> input) {
for (int i = 0; i < input.Count; ) {
var start = input[i];
int size = 1;
while (++i < input.Count && input[i] == start + size)
size++;
if (size == 1)
yield return start.ToString();
else if (size == 2) {
yield return start.ToString();
yield return (start + 1).ToString();
} else if (size > 2)
yield return start + " - " + (start + size - 1);
}
}
Python, 83 characters
def f(l,a=2):
for x in l:
b,a=a,(x+1in l)*(x-1in l)
if a<1:print',- '[b],`x`,
Demo:
>>> l=[1, 2, 3, 4, 7, 8, 10, 12, 13, 14, 15]
>>> f(l)
1 - 4 , 7 , 8 , 10 , 12 - 15
Python, 98 characters
def f(a):
for x in a:
if x-1not in a or x+1not in a:print x,"-"if x+1in a and x+2in a else",",
Python - 86 characters
This one doesn't include an extra ',' at the end
f=lambda a:''.join(`x`+",-"[(x+1in a)&x+2in a]for x in a if(x-1in a)&(x+1in a)^1)[:-1]
Ruby, 165 characters
a=[]
def o(a)print "#{@s}#{a[0]}#{"#{a.size<3?',':' -'} #{a[-1]}"if a.size>1}";@s=', 'end
ARGV[0].split(', ').each{|n|if a[0]&&a[-1].succ!=n;o(a);a=[]end;a<<n;};o(a)
C++, 166 characters
#define o std::cout
void f(std::vector<int> v){for(int i=0,b=0,z=v.size();i<z;)i==z-1||v[i+1]>v[i]+1?b?o<<", ":o,(i-b?o<<v[b]<<(i-b>1?" - ":", "):o)<<v[i],b=++i:++i;}
Don't you all just love abusing the ?:
operator? ;)
More readable version:
#define o std::cout
void f(std::vector<int> v){
for(int i=0,b=0,z=v.size();i<z;)
i==z-1||v[i+1]>v[i]+1 ?
b?o<<", ":o,
(i-b?o<<v[b]<<(i-b>1?" - ":", "):o)<<v[i],
b=++i
:++i;
}
Common Lisp, 442/206 chars
(defun d (l)
(if l
(let ((f (car l))
(r (d (cdr l))))
(if r
(if (= (+ f 1) (caar r))
(push `(,f ,(cadar r)) (cdr r))
(push `(,f ,f) r))
`((,f ,f))
))
nil))
(defun p (l)
(mapc #'(lambda (x)
(if (= (car x) (cadr x))
(format t "~a " (car x))
(if (= (+ 1 (car x)) (cadr x))
(format t "~a ~a " (car x) (cadr x))
(format t "~a-~a " (car x) (cadr x)))))
(d l)))
The "d" function rewrites the input list into a canonical form. For fun I did this entirely recursively. The "p" function formats the output to the equivalent of the reference implementation.
F#, 188 chars
let r(x::s)=
let f=printf
let p x=function|1->f"%A "x|2->f"%A %A "x (x+1)|n->f"%A-%A "x (x+n-1)
let rec l x n=function|y::s when y=x+n->l x (n+1)s|y::s->p x n;l y 1 s|[]->p x n
l x 1 s
More readable:
let range (x::xs) =
let f = printf
let print x = function
| 1 -> f "%A " x
| 2 -> f "%A %A " x (x+1)
| n -> f "%A-%A " x (x+n-1)
let rec loop x n = function
| y::ys when y=x+n ->
loop x (n+1) ys
| y::ys ->
print x n
loop y 1 ys
| [] ->
print x n
loop x 1 xs
Ruby : 123 characters
def y(n) t=[];r=[];n.each_with_index do |x,i| t<<x;if(x.succ!=n[i+1]);r=((t.size>2)?r<<t[0]<<-t[-1]:r+t);t=[];end;end;r;end
More Readable
def y(n)
t=[];r=[];
n.each_with_index do |x,i|
t << x
if (x.succ != n[i+1])
r = ((t.size > 2) ? r << t[0] << -t[-1] : r+t)
t=[]
end
end
r
end
And execute like
> n=[1, 2, 3, 4, 7, 8, 10, 12, 13, 14, 15]
> y n
=> [1, -4, 7, 8, 10, 12, -15]
PHP 95 chars
(actually it's the second language after python)
Given $a=array(numbers);
Algos:
for($i=0;$i<count($a);$i++){$c=$i;while($a[$i+2]==$a[$i]+2)$i++;echo $a[$c],$i-$c>1?'-':',';}
来源:https://stackoverflow.com/questions/4659511/code-golf-numeric-ranges