35
\$\begingroup\$

Disclaimer: while I have been on this site for entertainment purposes for a little while now, this is my first question, so please forgive any minor errors.

Background

When assigning us homework, my teacher is really annoying and writes out all the problems we have to do individually. As such, it takes me forever to copy down which problems I have to do. I thought to make my life easier, I would send him a program that could make the list of problems take up less space.

While writing down a list of page or problem numbers, we use a dash to denote a range. For example, 19-21 becomes 19, 20, 21. If there is a gap in between, two comma-separated ranges are used: 19-21, 27-31 becomes 19, 20, 21, 27, 28, 29, 30, 31.
Right about now, you're probably thinking: "this seems pretty trivial". In fact, this has already been answered here and here.

However, there is a catch. If we have a range with equal consecutive digits, the repeated digits can be left out. For example: 15, 16, 17 becomes 15-7, and 107, 108, 109 becomes 107-9. For a bonus, if the last consecutive equal digit is 1 greater and the upper limit's last digit is less than or equal to that of the lower, the following can be omitted (sorry if that sounded confusing; perhaps some examples will clear it up). 109-113 becomes 109-3, as a lower last digit implies increasing the 10s place.

Challenge

Your program should take a list of integers via input (whatever is standard for your language, or a function). You can decide whether this list is comma-separated, space-separated, or as an actual list/array.

Output the shortest way (first sorted by number of ranges, then the sum of the characters included in the ranges) to represent that list using this notation. Each dashed range must be on the same line, but the ranges can be separated by commas or newlines (trailing newlines or commas are allowed). These ranges must be in order.

Since our school Wi-Fi is terrible, I have to make the file as small as possible in order to send it to him. The shortest code (in bytes) wins.

Bonuses

My teacher is sloppy, so there are a few things that would help him out. Multiple bonuses stack through multiplication, e.g. a -10% bonus (x 90%) and a -25% (x 75%) bonus = 90% * 75% = x 67.5% (-32.5% bonus).

  • Sometimes he puts them in the wrong order (he's not a math teacher). Take a -20% bonus if your program can accept integers that are not sorted least-to-greatest.
  • Our book is weird, and each section starts counting the problems at -10. If your program can accept negative numbers, take a -25%.
  • If it accepts the bonus of a lower last digit increasing 10's place, e.g. 25-32 reducing to 25-2, take a -50% bonus.

Test Cases

In:  1, 2, 3, 4, 5
Out: 1-5

In:  3, 4, 5, 9, 10, 11, 12
Out: 3-5, 9-12

In:  149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160
Out: 149-60

In: 1 2 3 4
Out: 1-4


For bonuses:

In: 109, 110, 111, 112, 113
Out: 109-3

In:  19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29
Out: 19-9

In: -3, -2, -1, 0, 1, 2
Out: -3-2

In: -3, -2, -1
Out: -3--1

An answer will be accepted on Saturday, 19 December 2015.

GLHF!

\$\endgroup\$
  • \$\begingroup\$ Why is the output in the third test case not 1-4 9-2? \$\endgroup\$ – Alex A. Dec 11 '15 at 23:42
  • \$\begingroup\$ What should be output for a program that (a) does and (b) does not take the 50% bonus, for 149 150 151 152 153 154 155 156 157 178 159 160? \$\endgroup\$ – lirtosiast Dec 11 '15 at 23:46
  • 3
    \$\begingroup\$ I could've sworn there's another question just like this, but I can't find it... \$\endgroup\$ – mbomb007 Dec 12 '15 at 3:40
  • 5
    \$\begingroup\$ I think this is the related question everybody is thinking of. That one turns ranges into lists though. \$\endgroup\$ – Dennis Dec 12 '15 at 5:32
  • 1
    \$\begingroup\$ Another thing - the text says that the penultimate digit for the ending page of the range should be cut if it's lower than that of the start page, but the test case says 19-9 for 19,20,...,29 and not 19-29 as the text implies. So which is correct? \$\endgroup\$ – zocky Dec 15 '15 at 22:13

10 Answers 10

5
\$\begingroup\$

LabVIEW, 97*0.8*0.75*0.5 = 29.1 LabVIEW Primitives

this works by counting upwards if sucessive elemts are 1 apart and then creates a string from the the number and the number - count modulo 10 and some multiplication cause negatives are a bitch.

The gif showcases an input of 8,9,10,11 and outputs 8-1. For input -5,-4,-3,1,3,4,5 -5--3,1,3-5comes out.

\$\endgroup\$
  • 1
    \$\begingroup\$ Really, counting it as each for loop/while loop/if/whatever is 1 primitive isn't fair because in languages like JS, they count as more than 1 byte... \$\endgroup\$ – ev3commander Dec 16 '15 at 1:03
  • \$\begingroup\$ @ev3commander anything's fair if it comes with a cool animated diagram! \$\endgroup\$ – Cyoce Dec 16 '15 at 3:03
  • \$\begingroup\$ thats why its in primitives not bytes. Also theres a lot of wiring going on so the loops actaully are 2 or 3 at least and also another 3 per shift register + initialisation. \$\endgroup\$ – Eumel Dec 16 '15 at 8:50
  • 1
    \$\begingroup\$ by standard golf rules you can do that, its just boring \$\endgroup\$ – Eumel Dec 16 '15 at 22:09
  • 2
    \$\begingroup\$ @ev3commander Actually, if the language is newer than the challenge you are not allowed to use it for competitive reasons. \$\endgroup\$ – Adnan Dec 18 '15 at 10:05
14
\$\begingroup\$

C++11, 451 * 80% * 75% * 50% = 135.3 bytes

Saved 9 bytes thanks to @kirbyfan64sos.

Saved 19 bytes thanks to @JosephMalle and @cat.

Saved 11 bytes thanks to @pinkfloydx33.

#include<vector>
#include<cmath>
#include<algorithm>
#include<string>
#define T string
#define P append
using namespace std;T f(vector<int>v){sort(v.begin(),v.end());T r=to_T(v[0]);int b=1;int m=v[0];for(int i=1;i<=v.size();i++){if(i!=v.size()&&v[i]==v[i-1]+1){if(!b){m=v[i-1];}b=1;}else{if(b){T s=to_T(v[i-1]);r.P("-").P(s.substr(s.size()-(v[i-1]-m==1?1:log10(v[i-1]-m)),s.size()));}if(i!=v.size()){r.P(", ").P(to_T(v[i]));}b=0;}}return r;}

This qualifies for all the bonuses.

Sample parameter test and result:

In:  [1, 2, 3, 4, 5]
Out: 1-5

In:  [3, 4, 5, 9, 10, 11, 12]
Out: 3-5, 9-12

In:  [149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160]
Out: 149-60

In:  [1, 2, 3, 4]
Out: 1-4

In:  [109, 110, 111, 112, 113]
Out: 109-3

In:  [19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
Out: 19-9
\$\endgroup\$
  • \$\begingroup\$ Why not use int instead of unsigned int? Saves 9 bytes. \$\endgroup\$ – kirbyfan64sos Dec 13 '15 at 23:05
  • \$\begingroup\$ @kirbyfan64sos Thanks, didn't notice that. \$\endgroup\$ – TheCoffeeCup Dec 14 '15 at 0:21
  • \$\begingroup\$ +1 always like to see C++. I can't test this, but I don't think you need iostream \$\endgroup\$ – sudo rm -rf slash Dec 15 '15 at 3:02
  • \$\begingroup\$ I don't think you need iostream either, but gcc gave: a.cpp: In function ‘std::string f(std::vector<int>)’: a.cpp:8:83: error: ‘to_string’ was not declared in this scope \$\endgroup\$ – cat Dec 15 '15 at 3:47
  • \$\begingroup\$ @cat Make sure it's updated enough that it supports the C++11 standard. 4.3-ish should be good with -std=c++11; >= 5.0 has it on by default (actually it's -std=gnu11, but close enough). \$\endgroup\$ – Mego Dec 15 '15 at 4:39
8
+100
\$\begingroup\$

Ruby, 120 118 * 0.8 * 0.75 * 0.5 = 35.4 bytes

Takes command-line arguments as input (commas are okay); prints one range per line to standard output.

c=(b=(a=$*.map(&:to_i).sort).map &:succ)-a
puts (a-b).map{|m|(m<n=c.shift-1)?"#{m}-#{m<0?n:n%10**"#{n-m-1}".size}":m}

With whitespace/comments:

c=(
  b=(
    # a is the sorted input
    a=$*.map(&:to_i).sort
  # b is the set of successors of elements of a
  ).map &:succ
# c=b-a is the set of not-quite-least upper bounds of our ranges
)-a

# a-b is the set of greatest lower bounds of our ranges
puts (a-b).map {|m|
  # for each range [m,n], if there are multiple elements
  (m < n = c.shift-1) ?
    # yield the range, abbreviating n appropriately if positive
    "#{m}-#{m<0 ? n : n % 10 ** "#{n-m-1}".size}" :
    # in the one-element case, just yield that
    m
}

Test cases

$ ruby homework.rb 1, 2, 3, 4, 5
1-5

$ ruby homework.rb 3, 4, 5, 9, 10, 11, 12
3-5
9-2

$ ruby homework.rb 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160
149-60

$ ruby homework.rb 1 2 3 4
1-4

$ ruby homework.rb 109, 110, 111, 112, 113
109-3

$ ruby homework.rb 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29
19-9

Features not covered by test cases

Unordered input & single-element ranges:

$ ruby homework.rb 2 17 19 22 0 1 8 20 18
0-2
8
17-0
22

Negative ranges (not possible to abbreviate the larger number with these):

$ ruby homework.rb -17 -18 -19 -20 -21
-21--17

Abbreviation of arbitrary numbers of digits (ordinary bash expansion used for the input here):

$ ruby homework.rb {1234567..1235467} 2345999 2346000 2346001
1234567-467
2345999-1
\$\endgroup\$
  • \$\begingroup\$ I believe you can replace ((n=c.shift-1)>m) with m<n=c.shift-1 \$\endgroup\$ – Cyoce Oct 21 '16 at 0:33
5
\$\begingroup\$

Javascript ES6, 229 * 80% * 75% * 50% = 68.7 bytes

Test Input

I'm using the following test data:

var A1=[
  5,6,7,            // => 5-7     # (a) group pages 
  2,3,              // => 2-3,5-7 # (b) must be properly sorted
  -9,-8,-7,         // => -10--8  # (c) allow negative numbers
  29,30,31,32,      // => 29-2    # (d) lower last digit implies increasing the 10s place
  9,10,11,12,       // => 9-11    # NOT 9-2
  36,37,38,39,40,41,42,43,44,45,46,47, 
                    // => 36-47   # NOT 36-7
  99,100,101,102,   // => 99-102  # NOT 99-2
  109,110,111,112,  // => 109-2   # NOT 109-12
],
// more tests, not specified in the question
A2=[
  120,124,       // => 120,124 # (e) handle single pages
],
A3=[
  135,136,135    // => 135-6   # (f) handle duplicates
];

Basic: 229 bytes

This version satisfies the requirements of the question (a) with all bonuses (c,d,e), but hangs on single pages. It can also handle duplicates(f). It handles negative pages down to -10,000, which can be easily increased with (large) loss of speed.

F=(a)=>{var R=[],i=NaN,l,u;a.map(x=>R[1e4+x]=x);R.concat('').map(x=>(i!=i&&(l=x,u=l-1),i=0,u=(x+="")-u-1?l=console.log(l+'-'+(u>0?(l.length-u.length||(z=>{for(;l[i]==u[i];i++);})(),u.length-i-2||u-l>9||i++,u.slice(i)):u))||x:x))}
F(A1.concat(A3)) --> -9--7 2-3 5-7 9-12 29-2 36-47 99-102 109-2 135-136

(The output above shows spaces instead of actual newlines for brevity)

Single pages: 233 bytes

This slightly longer version additionally satisfies (e) and displays single pages as a range with equal lower and upper limits

G=(a)=>{var R=[],i=NaN,l,u;a.map(x=>R[1e4+x]=x);R.concat('').map(x=>(i!=i&&(l=x,u=l-1),i=0,u=(x+="")-u-1?l=console.log(l+'-'+(u-l&u>0?(l.length-u.length||(z=>{for(;l[i]==u[i];i++);})(),u.length-i-2||u-l>9||i++,u.slice(i)):u))||x:x))}
G(A1.concat(A2,A3)) --> -9--7 2-3 5-7 9-12 29-2 36-47 99-102 109-2 120-120 124-124
\$\endgroup\$
  • \$\begingroup\$ @Cyoce - Are you using an ES6-enabled javascript engine? \$\endgroup\$ – zocky Dec 15 '15 at 4:39
  • \$\begingroup\$ Oh, hmm, I have a bug, it doesn't actually handle 36-47 correctly. What's the proper procedure? Do I delete it and fix it, or just try to fix it (I may not have the time right now), or what? \$\endgroup\$ – zocky Dec 15 '15 at 4:47
  • \$\begingroup\$ Hmm, it just works in my Chrome. What gives? \$\endgroup\$ – zocky Dec 15 '15 at 4:50
  • \$\begingroup\$ And zocky, fix it when you can. It just won't count as valid until it's fixed, and as such can not be accepted until then (assuming yours is the fewest bytes). \$\endgroup\$ – Cyoce Dec 15 '15 at 4:51
  • \$\begingroup\$ Let us continue this discussion in chat. \$\endgroup\$ – Cyoce Dec 15 '15 at 4:51
3
\$\begingroup\$

GAP, 355 Bytes *0.8*0.75*0.5 = 106.5

This satisfies all the bonuses. It cost me almost 100 extra bytes to make everything work nicely. This function only omits leading digits if the gap does not overflow the ones place once. For example 9 10 11 outputs 9-1 but 9 10 11 12 .. 20 21 outputs 9-21.

If GAP was a little less verbose, I could have gotten this pretty short (also could have saved many bytes if I didn't follow the exact syntax.) I'll probably try golfing this a bit harder tomorrow. See below for test cases.

g:=function(l)local n;if not l=[] then Sort(l);n:=1;while not l=[] do;if not IsSubset(l,[l[1]..l[1]+n]) then if not n=1 then if n-1>10-l[1] mod 10 and n-1<11 then Print(l[1],"-",(l[1]+n-1) mod 10);else Print(l[1],"-",l[1]+n-1);fi;else Print(l[1]);fi;Print(", ");SubtractSet(l,[l[1]..l[1]+n-1]);g(l);fi;n:=n+1;od;fi;Print("\b\b  ");end; 

ungolfed:

g:=function(l)
    local n;
    if not l=[] then
        Sort(l);
        n:=1;
        while not l=[] do;
            if not IsSubset(l,[l[1]..l[1]+n]) then
                if not n=1 then
                    if n-1>10-l[1] mod 10 and n-1<11 then
                        Print(l[1],"-",(l[1]+n-1) mod 10);
                    else
                        Print(l[1],"-",l[1]+n-1);
                    fi;
                else
                    Print(l[1]);
                fi;
                Print(", ");
                SubtractSet(l,[l[1]..l[1]+n-1]);
                g(l);
            fi;
            n:=n+1;
        od; 
    fi;
    Print("\b\b  ");
end;

Note that in GAP syntax, [a..b] is equivalent to [a,a+1,...,b]. I believe that these test cases demonstrate that this program meets all the requirements. If something is wrong, let me know.

gap> h([1..5]);
1-5  
gap> h([3,4,5,9,10,11,12]);
3-5, 9-2  
gap> h([149..160]);
149-160  
gap> h([109..113]);
109-3  
gap> h([19..29]);
19-9  

gap> h([-1,-2,-3,-7,-20000,9,10,110101,110102]);
-20000, -7, -3--1, 9-10, 110101-110102  

gap> h([10101,10102,10103,10,11,12,13,14,15,16,234,999,1000,1001,1002]);
10-16, 234, 999-2, 10101-10103  
\$\endgroup\$
3
\$\begingroup\$

Lua, 322*80%*75%*50% = 96.6 Bytes

Finally done with the 3 challenges, Scores under 100 bytes :D

Golfed

function f(l)table.sort(l)l[#l+1]=-13 a=l[1]t,s=a,"" for _,v in next,l do if v-t>1 or t-v>1 then s,p,r=s..a.."-",""..t,""..a r:gsub("%d",function(c)p=r:find(c)~=r:len()and p:gsub("^(-?)"..c,"%1")or p r=r:gsub("^"..c,"")end)p=t-a<10 and t%10<a%10 and p:gsub("^(%d)","")or p s,a,t=s..p..",",v,v else t=v end end return s end

Ungolfed

function f(l)
    table.sort(l)
    l[#l+1]=-13 
    a=l[1] 
    t,s=a,"" 
    for _,v in next,l 
    do
        if v-t>1 or t-v>1
        then
            s,p,r=s..a.."-",""..t,""..a
            r:gsub("%d",function(c)
                p=r:find(c)~=#r and p:gsub("^(-?)"..c,"%1")or p
                r=r:gsub("^"..c,"")
            end)
            p=t-a<10 and t%10<a%10 and p:gsub("^(%d)","")or p
            s=s..p..","
            a,t=v,v
        else
            t=v
        end
    end
return s
end

You can test lua online, to see how it perform against the test cases, copy paste the function, followed by this code :

a={1,2,3,4,5}
b={3,4,5,9,10,11,12,13,14,15,16,17,18,19,20,21}
c={149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160}
d={-7,8,5,-6,-5,6,7}
print(f(a))
print(f(b))
print(f(c))
print(f(d))
\$\endgroup\$
  • \$\begingroup\$ Seems to fail if {9..21} is entered. Outputs 9-1. \$\endgroup\$ – Liam Dec 16 '15 at 9:23
  • \$\begingroup\$ @ICanHazHats Fixed, thanks for pointing it out :) \$\endgroup\$ – Katenkyo Dec 16 '15 at 9:55
2
\$\begingroup\$

Java, 252 * 80% * 75% * 50% = 75.6 bytes

I've decided to go for a method (is much smaller in Java), here is the golfed version:

Golfed

int p,c,s;String m(int[]a){p=s=c=0;c--;String o="";Arrays.sort(a);for(int n:a){if(s==0)o+=s=n;else if(n-p==1)c++;else{o+=t()+", "+(s=n);c=-1;}p=n;}return o+t();}String t(){return c>=0?"-"+(""+p).substring((""+Math.abs(p)).length()-(""+c).length()):"";}

And here is the readable version:

int p, c, s;

String m(int[] a) {
    p = s = c = 0;
    c--;
    String o = "";
    Arrays.sort(a);
    for (int n : a) {
        if (s == 0)
            o += s = n;
        else if (n - p == 1)
            c++;
        else {
            o += t() + ", " + (s = n);
            c = -1;
        }
        p = n;
    }
    return o + t();
}

String t() {
    return c >= 0 ? "-" + ("" + p).substring(("" + Math.abs(p)).length() - ("" + c).length()) : "";
}

When tested these are the results:

import java.util.Arrays;
public class A {
    public static void main(String...s) {
        A a = new A();
        System.out.println(a.m(new int[] {1, 2, 3, 4, 5}));
        System.out.println(a.m(new int[] {3, 4, 5, 9, 10, 11, 12}));
        System.out.println(a.m(new int[] {149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160}));
        System.out.println(a.m(new int[] {109, 110, 111, 112, 113}));
        System.out.println(a.m(new int[] {19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29}));
        System.out.println(a.m(new int[] {1,10,11,16}));
        System.out.println(a.m(new int[] {-3,-2,-1,0,1,2,3}));
        System.out.println(a.m(new int[] {-3,-2,-1}));
    }

    int p,c,s;String m(int[]a){p=s=c=0;c--;String o="";Arrays.sort(a);for(int n:a){if(s==0)o+=s=n;else if(n-p==1)c++;else{o+=t()+", "+(s=n);c=-1;}p=n;}return o+t();}String t(){return c>=0?"-"+(""+p).substring((""+Math.abs(p)).length()-(""+c).length()):"";}
}

Output:

1-5
3-5, 9-2
149-60
109-3
19-9
1, 10-1, 16
-3-3
-3--1

Update:

It can now handle negative numbers as well, adding to the bonus.

\$\endgroup\$
  • \$\begingroup\$ I'm no Java expert, but could you shorten it by changing p=s=c=0;c--; to p=s=0;c=-1; ? \$\endgroup\$ – Cyoce Dec 16 '15 at 23:35
  • \$\begingroup\$ I'm no Java expert, but could you shorten it by changing return c >= 0 ? "bla" : "" to return c < 0 ? "": "bla" ? \$\endgroup\$ – Stephan Schinkel Dec 18 '15 at 10:50
  • \$\begingroup\$ you could even do c=~(p=s=0) for style points. \$\endgroup\$ – Cyoce Dec 18 '15 at 23:17
2
\$\begingroup\$

Japt, 127 bytes * 80% * 75% * 50% = 38.1

Wow, that was one heck of a challenge to include all the bonuses. It could probably be made shorter.

D=[]N=Nn-;DpNr@Y-1¥Xg1 ?[Xg Y]:DpX ©[YY]}D;Ds1 £[BC]=Xms;B¥C?B:B+'-+CsBg ¦'-©Cl ¥Bl ©C¬r@B¯Z ¥C¯Z ªC-B§ApCl -Z ©ÂBsX <ÂCsX ?Z:X

Try it online!

How it works

The explanation is very rough; don't hesitate to ask any questions you might have.

/*    Setting up basic variables    */
                      // Implicit: A = 10, N = list of input numbers.
D=[],N=Nn-;           // D = empty array, N = N sorted by subtraction.

/*    Finding ranges of page numbers    */    
Dp                    // Push into D the result of
NrXYZ{                // reducing each previous value X and item Y in N by this function,
}[];                  // starting with an empty array:
 Y-1==Xg1 ?           //  If Y is 1 more than the second item of X,
 [Xg Y]:              //   return [X[0], Y].
 DpX &&[YY]           //  Otherwise, push X into D and return [Y, Y].

/*    Formatting result    */
Ds1 mXYZ{             // Take the first item off of D and map each item X by this function:
 [BC]=Xms;            //  Set B and C to the first to items in X as strings.
 B==C?B               //  If B is the same as C, return B.
 :B+'-+Cs             //  Otherwise, return B + a hyphen + C.slice(
  Bg !='-&&           //   If B[0] is not a hyphen (B is not negative), AND
  Cl ==Bl &&          //   B and C are the same length,

  /*    Cutting off unnecessary digits    */
  Cq r                //    then C split into digits, reduced with
  rXYZ{               //    each previous value X, item Y, and index Z mapped by this function:
   Bs0,Z ==Cs0,Z ||   //     If B.slice(0,Z) equals C.slice(0,Z), OR
   C-B<=ApCl -Z       //     C - B <= 10 to the power of (C.length - Z);
   &&~~BsX <~~CsX     //     AND B.slice(X) is a smaller number than C.slice(X),
   ?Z:X               //     then Z; otherwise, X.
                      //   Otherwise, 0.
\$\endgroup\$
1
\$\begingroup\$

R, 167 bytes x 80% x 75% x 50% -> 50.1

s=sort(scan(se=","));r=c();while(length(s)){w=s==1:length(s)+s[1]-1;x=s[w];s=s[!w];z=tail(x,1);r=c(r,paste0(x[1],"-",ifelse(z-x[1]<=10,z%%10,z%%100)))};cat(r,sep=", ")

Indented, with new lines:

s=sort(scan(se=","))
r=c()
while(length(s)){
w=s==1:length(s)+s[1]-1
x=s[w]
s=s[!w]
z=tail(x,1)
r=c(r, paste0(x[1],"-", ifelse(z-x[1]<=10, 
                               z%%10,
                               z%%100)))}
cat(r,sep=", ")

Test cases:

> s=sort(scan(se=","));r=c();while(length(s)){w=s==1:length(s)+s[1]-1;x=s[w];s=s[!w];r=c(r,paste0(x[1],"-",ifelse(tail(x,1)-x[1]<=10,tail(x,1)%%10,tail(x,1)%%100)))};cat(r,sep=", ")
1: 3, 4, 5, 9, 10, 11, 12
8: 
Read 7 items
3-5, 9-2
> s=sort(scan(se=","));r=c();while(length(s)){w=s==1:length(s)+s[1]-1;x=s[w];s=s[!w];r=c(r,paste0(x[1],"-",ifelse(tail(x,1)-x[1]<=10,tail(x,1)%%10,tail(x,1)%%100)))};cat(r,sep=", ")
1: 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160
13: 
Read 12 items
149-60

It works for the -50% bonus:

> s=sort(scan(se=","));r=c();while(length(s)){w=s==1:length(s)+s[1]-1;x=s[w];s=s[!w];r=c(r,paste0(x[1],"-",ifelse(tail(x,1)-x[1]<=10,tail(x,1)%%10,tail(x,1)%%100)))};cat(r,sep=", ")
1: 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29
12: 
Read 11 items
19-9
> s=sort(scan(se=","));r=c();while(length(s)){w=s==1:length(s)+s[1]-1;x=s[w];s=s[!w];r=c(r,paste0(x[1],"-",ifelse(tail(x,1)-x[1]<=10,tail(x,1)%%10,tail(x,1)%%100)))};cat(r,sep=", ")
1: 109, 110, 111, 112, 113
6: 
Read 5 items
109-3

It accepts unsorted input:

> s=sort(scan(se=","));r=c();while(length(s)){w=s==1:length(s)+s[1]-1;x=s[w];s=s[!w];r=c(r,paste0(x[1],"-",ifelse(tail(x,1)-x[1]<=10,tail(x,1)%%10,tail(x,1)%%100)))};cat(r,sep=", ")
1: 114, 109, 110, 111, 112, 113
7: 
Read 6 items
109-4

It accepts negative numbers:

> s=sort(scan(se=","));r=c();while(length(s)){w=s==1:length(s)+s[1]-1;x=s[w];s=s[!w];r=c(r,paste0(x[1],"-",ifelse(tail(x,1)-x[1]<=10,tail(x,1)%%10,tail(x,1)%%100)))};cat(r,sep=", ")
1: -1,0,1,2
4: 
Read 3 items
-1-2
\$\endgroup\$
0
\$\begingroup\$

sh, 135 * .8 * .75 * .5 = 40.5

tr , \\n|sort -n|awk -vORS="" '$1-o>1||!c{print p c$1;s=$1}{o=$1;c=", ";p=""}o>s{p="-"substr(o,length(o)-length(o-s-1)+1)}END{print p}'

shell script

tr , \\n|           # comma separated -> newline separated
sort -n|            # sort
awk -vORS=""        # suppress automatic newlines in output

awk script

# on step > 1 or first run, end the current sequence and start a new one.
# on first run, p and c are empty strings.
$1-o>1||!c
    {print p c$1;s=$1}

# old = current, c = ", " except for first run, clear end string.
    {o=$1;c=", ";p=""}

# if the sequence is not a single number, its end is denoted by "-o".
# print only the last n digits of o.
o>s
    {p="-"substr(o,length(o)-length(o-s-1)+1)}

# end the current sequence without starting a new one.
END
    {print p}'

where s is the start of the current sequence and o is the previous input value.

\$\endgroup\$
  • \$\begingroup\$ I like it, but it doesn't get the -25% bonus currently. substr() is chopping off minus signs and significant digits. \$\endgroup\$ – ezrast Dec 17 '15 at 23:21
  • \$\begingroup\$ @ezrast This is actually correct behaviour in terms of the -50% bonus: -31, -30, -29, -28 increases in the 10's place from -3 to -2 and shall therefore be condensed to -31-8. I also see the ambiguity it creates, but that's what is asked for. \$\endgroup\$ – Rainer P. Dec 20 '15 at 13:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.