Code Golf: Numeric Ranges

1.8k views Asked by At

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);
    }
}
8

There are 8 answers

4
Jules Olléon On BEST ANSWER

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
0
Samuel On

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)
2
Keith Randall On

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]
0
Timo On

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;
}
0
Markus Jarderot On

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
0
Dr. Pain On

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.

0
RameshVel On

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]
2
dynamic On

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?'-':',';}