Return each number from a group of numbers

11

The challenge

The program must return all numbers included into a group (comma and hyphen separated sequence) of numbers.

Rules

  • s is the sequence string;
  • all numbers included in s are positive;
  • numbers will always increase;
  • numbers will never repeat
  • when you answer, show the output for s="1,3-5,9,16,18-23"

Examples

input(s)    outputs
-----------------
1           1
1,2         1,2
1-4         1,2,3,4
1-4,6       1,2,3,4,6
1-4,8-11    1,2,3,4,8,9,10,11

Good luck. =)

BernaMariano

Posted 2012-10-03T16:25:30.007

Reputation: 329

Does it have to be a full program, and is there a restriction on the format of the output? – Brad Gilbert b2gills – 2015-11-28T19:21:01.017

1duplicate? – ev3commander – 2015-11-28T21:53:57.647

1Will we ever have input sequences that are not constantly increasing, for example: 4-9,1-2 or 1-3,9-6? – Matt – 2012-10-03T17:16:12.513

1Or overlapping? Does the output have to be sorted and not contain duplicates? – Peter Taylor – 2012-10-03T17:24:38.127

@Gareth Yes, this is a code-golf, then please vote-up for the shortest answer. Matt and Peter, I edited the question, please check it. Thanks! – BernaMariano – 2012-10-03T17:33:03.293

Answers

6

GolfScript (24 chars)

','/{~.,!{~)),>~}*}%','*

E.g.

$ golfscript.rb expand.gs <<<"1,3-5,9,16,18-23"
1,3,4,5,9,16,18,19,20,21,22,23

I actually have four 24-char solutions, but I chose this one because it doesn't have any alphanumeric characters.

How it works

# On the stack: a string such as "1,3-5,9,16,18-23"
','/
# Split on commas to get ["1" "3-5" "9" "16" "18-23"]
{
    # This is executed for each of those strings in a map
    # So stack holds e.g. "1" or "3-5"

    # Evaluate the string.
    # If it's a single number, this puts the number on the stack.
    # Otherwise it's parsed as a positive number followed by a negative number.
    ~
    # Stack holds e.g. 1 or 3 -5
    # Duplicate the last element on the stack and make a list of that length.
    # If it's negative or zero, the list will be empty
    .,
    # Negate. An empty list => 1; a non-empty list => 0
    !
    # If the string was a single number "n", the stack now holds n 0
    # If the string was a range "m-n", the stack now holds m -n 1
    # The following block will be executed 0 times for "n" and once for "m-n"
    {
        # Here we rely on twos-complement numbers satisfying ~n = -n -1
        # Stack: m -n
        ~))
        # Stack: m -(-n)-1+2  =  m n+1
        ,
        # Stack: m [0 1 2 ... n]
        >
        # Stack: [m m+1 ... n]
        ~
        # Stack: m m+1 ... n
    }*
}%
# On the stack: e.g. [1 3 4 5 9 16 18 19 20 21 22 23]
','*
# Joined by , to give the desired output

Peter Taylor

Posted 2012-10-03T16:25:30.007

Reputation: 41 901

How can you expand 3-5 into 3,4,5 without using a single the character -? – BernaMariano – 2012-10-04T20:20:32.363

@BernaMariano, sorry, I somehow missed your question. I'll expand the answer with a detailed explanation. – Peter Taylor – 2012-11-09T21:53:07.623

7

Perl 25 26 25

$_ is the sequence string

s/-/../g;$_=join",",eval

Sample session:

[~/] $ perl -M5.010 -pe 's/-/../g;$_=join",",eval' <<< "1,3-5,9,16,18-23"
1,3,4,5,9,16,18,19,20,21,22,23

Added 1 character to the character count for the -n-p option (thanks Gareth, ..kinda).

ardnew

Posted 2012-10-03T16:25:30.007

Reputation: 2 177

Remove -M5.010 and exchange -e for -E – Brad Gilbert b2gills – 2015-11-28T19:31:12.793

I've probably done the character counting wrong (with the command line options). Feel free to correct my counting, please – ardnew – 2012-10-03T18:57:58.473

Going by the answer to this question on meta, you only need to add 1 character for the n option.

– Gareth – 2012-10-03T19:03:08.887

4

R, 44 bytes

`-`=seq;eval(parse(t=c("c(",scan(,""),")")))

Try it online!

Redefine - to mean seq (i.e. :), surround the input with c() and evaluate the corresponding expression.

Robin Ryder

Posted 2012-10-03T16:25:30.007

Reputation: 6 625

4

golfscript, 46 45

My first ever golf script program, took hours to complete.

{','/{'-'/{~}%.,1-{))+{,}/\-~}{~}if}%","*}:r; 

# call:
"1,3-5,9,16,18-23"r

# return:
1,3,4,5,9,16,18,19,20,21,22,23

You can try it at http://golfscript.apphb.com/

My best throw at explaining this atrocity:

{...}:r;     # makes a function block ... and names it r

','/         # slices the top element of stack from each ','
             # so we get ["1" "3-5" "9" "16" "18-23"]

{...}%       # makes a function block ... and calls it for 
             # each element in the list

'-'/{~}%     # slices the list by '-' and evals each element 
             # from string to int. ["1"] becomes [1], 
             # ["3-5"] becomes [3 5]

.,1-         # adds the length of the list -1 on top of the stack
             # so for [1] the stack becomes [1] 0, for [3 5]
             # it becomes [3 5] 1

# next we add two function blocks, they, like the 0/1 just before
# are used by an if clause a tiny bit later. First block is for 
# lists that have a 1 on top of them, the latter for ones with 0.

# First block, we have something like [3 5]

))+          # pops the top element of the array, increments 
             # it and puts back. [3 6]

## It seems {...}%~ is same as {...}/
## this is why these two are not in the code any more

{,}%         # , makes a list from 0 to n-1, where n is the parameter
             # so we get [[0 1 2] [0 1 2 3 4 5]]

~            # Dumps the outer array, [0 1 2] [0 1 2 3 4 5]

\            # swaps the two arrays

-            # set complement [3 4 5]

~            # dumps the array, so the elements are left in the stack

# Second block, we have something like [16]

~            # just dumps the array, 16

# Blocks end

if           # takes the top three elements of the stack, evaluates the 
             # first (0 or 1), runs second if true (anything but 
             # [], "", 0 or {} ), otherwise the third.

","*         # joins an array with ","

edit 1: changed the last {}%~ to {}/, also my description was likely wrong.

shiona

Posted 2012-10-03T16:25:30.007

Reputation: 2 889

2+1, because anyone doing a program in GolfScript has earned it. – Gareth – 2012-10-03T21:37:10.603

@Gareth Thanks. I first thought I'd just do it the perl way: change - to .. and evaluate it. Then I couldn't find any sane way to build any arrays so I did this. I'm sure someone will come around with a ~20 char solution with golfscript. – shiona – 2012-10-03T22:20:44.417

I have 24 at the moment, so I'll take 20 as a challenge ;) You can save a few quite easily, though. The problem asks for a program, not a function, so you can lose the initial { and the final }:r; and you can also save one by replacing 1- with (. (Incidentally, IIRC that's one trick I also missed in my first GolfScript program) – Peter Taylor – 2012-10-03T22:32:54.567

PS There is a subtle difference between {...}%~ and {...}/. If you're accessing something further down the stack using integer $ then the first one is simpler, because you don't have to adjust the integer each time to compensate for whatever you're leaving on the stack. – Peter Taylor – 2012-10-03T22:34:34.813

3

Jelly, 9 bytes

⁾-ryṣ”,VF

Try it online!

   y         Replace
⁾-r          hyphens with the letter r,
    ṣ”,      split on commas,
       V     evaluate every element,
        F    and flatten.

The range dyad r takes two arguments on either side of it and produces an inclusive range between them.

Unrelated String

Posted 2012-10-03T16:25:30.007

Reputation: 5 300

3

K, 47

","/:,/${x+!1+y-x}.'2#'a,'a:"I"$'"-"\:'","\:0:0

Test case

k)","/:,/${x+!1+y-x}.'2#'a,'a:"I"$'"-"\:'","\:0:0
1,3-5,9,16,18-23
"1,3,4,5,9,16,18,19,20,21,22,23"

tmartin

Posted 2012-10-03T16:25:30.007

Reputation: 3 917

","/:$,/{{x+!1+y-x}. 2#"J"$"-"\:x}'","\:0:0 for 43 bytes – streetster – 2019-07-19T21:45:27.963

2

Hassium, 173 Bytes

This was pretty long and might not be competing since there is a trailing , at the end.

 func main(){p="1,2,3,5-8".split(",")for(c=0;c<p.length;c++){e=p[c]if(e.contains("-")){p=e.split("-")for(x=p[0].toInt();x<=p[1].toInt()print(x++ +",")){}}else print(e+",")}}

Run online and see expanded here

Jacob Misirian

Posted 2012-10-03T16:25:30.007

Reputation: 737

2

J, 53 43 41 39 38 characters

;(}.[:i.1+])/&.>".'- ,;'charsub 1!:1[1

Takes input from the keyboard:

   ;(}.[:i.1+])/&.>".'- ,;'charsub 1!:1[1
1-4,8-11
1 2 3 4 8 9 10 11

Output for the requested test case:

   ;(}.[:i.1+])/&.>".'- ,;'charsub 1!:1[1
1,3-5,9,16,18-23
1 3 4 5 9 16 18 19 20 21 22 23

Gareth

Posted 2012-10-03T16:25:30.007

Reputation: 11 678

1

K (oK), 40 31 bytes

Solution

,/{{x+!1+y-x}. 2#.:'"-"\x}'","\

Try it online!

Explanation:

Managed more golfing whilst adding the explanation...

,/{{x+!1+y-x}. 2#.:'"-"\x}'","\ / the solution
                           ","\ / split input on ","
  {                      }'     / apply lambda to each
                    "-"\x       / split x on "-"
                 .:'            / value (.:) each (')
               2#               / 2 take (dupe if only 1 element)
   {        }.                  / diadic lambda, 2 args x and y
         y-x                    / y subtract x
       1+                       / add 1
      !                         / range 0..n
    x+                          / add x
,/                              / flatten

streetster

Posted 2012-10-03T16:25:30.007

Reputation: 3 635

1

PowerShell, 79 71 bytes

('('+($args[0]-replace'-','..'-replace',','),(')+')'|iex|%{$_})-join','

Try it online!

The inner part changes "1,5-9,12" into a "(1),(5..9),(12)" format that PowerShell understands, then executes that with iex, which creates an array of arrays. Then iterate through each inner array, then finally join all outer array elements together

Borrows code from my "Help Me Manage My Time" answer

Usage

PS C:\Tools\Scripts\golfing> .\return-each-number-from-a-group-of-numbers.ps1 '1,3-5,9,16,18-23'
1,3,4,5,9,16,18,19,20,21,22,23

-8 bytes thanks to Veskah

AdmBorkBork

Posted 2012-10-03T16:25:30.007

Reputation: 41 581

You're doing redundant joins, 71 bytes – Veskah – 2019-06-24T19:24:23.903

1

Python 2.7, 147 138 Bytes

z,f=input().split(','),[]
for i in z:
 x=i.split('-')
 if len(x)>1:f+=range(int(x[0]),int(x[1])+1)
 else:f+=[int(x[0])]
print str(f)[1:-1]

Usage:

>>>python nums.py
"1,3-5,9,16,18-23"
1, 3, 4, 5, 9, 16, 18, 19, 20, 21, 22, 23

Not the best program...

Alex

Posted 2012-10-03T16:25:30.007

Reputation: 417

1Welcome to PPCG. I think you can make your answer shorter by using 1 space for indents. – intrepidcoder – 2015-11-26T02:42:03.420

Thanks @intrepidcoder, I didn't know that you could use single space indents. – Alex – 2015-11-27T01:26:16.267

1

MATLAB, 47 bytes

disp(eval(['[',strrep(input(''),'-',':'),']']))

This snippet reads a string input from the command window, replaces '-' by ':', adds square brackets to the string and then evaluates it, so that the input will be expanded to a full array of numbers.

Example input:

'1,3-5,9,16,18-23'

Example output:

1     3     4     5     9    16    18    19    20    21    22    23

I believe this output is allowed, as the challenge only say that all numbers in a group should be displayed.

slvrbld

Posted 2012-10-03T16:25:30.007

Reputation: 619

comma-separated output would be nicer, though i can se a 5-spaces-separated pattern, thats cool for me :) – BernaMariano – 2015-11-27T14:05:30.863

1

Perl 6, 36 bytes

$_=get;say join ',',EVAL S:g/\-/../
1,3,4,5,9,16,18,19,20,21,22,23

Brad Gilbert b2gills

Posted 2012-10-03T16:25:30.007

Reputation: 12 713

1

Perl (37)

$_=<>;s/^/say join',',/;s/-/../g;eval

marinus

Posted 2012-10-03T16:25:30.007

Reputation: 30 224

How about say join",",eval<>=~s/-/../gr at 29 bytes – Brad Gilbert b2gills – 2015-11-28T19:15:35.793

>

  • when you answer, show the output for s="1,3-5,9,16,18-23", thanks
  • < – BernaMariano – 2012-10-03T17:40:22.377

    0

    Clojure, 110 bytes

    #(clojure.string/join","(for[s(.split %",")[a b][(map read-string(.split s"-"))]r(if b(range a(inc b))[a])]r))
    

    Dealing with strings isn't much fun :(

    NikoNyrh

    Posted 2012-10-03T16:25:30.007

    Reputation: 2 361

    0

    Python 2, 112 bytes

    Pretty simple and straightforward answer.

    L=[]
    for s in input().split(','):
     if'-'in s:a,b=map(int,s.split('-'));L+=range(a,b+1)
     else:L+=[int(s)]
    print L
    

    Try it online!

    mbomb007

    Posted 2012-10-03T16:25:30.007

    Reputation: 21 944

    0

    Ruby -p, 33 bytes

    gsub(/(\d+)-(\d+)/){[*$1..$2]*?,}
    

    Try it online!

    Value Ink

    Posted 2012-10-03T16:25:30.007

    Reputation: 10 608

    0

    Japt, 12 bytes

    q, c@OvXr-'ò
    

    Try it

    Shaggy

    Posted 2012-10-03T16:25:30.007

    Reputation: 24 623

    Can you replace c@ with £? – Oliver – 2019-07-19T20:07:43.117

    @Oliver, as it's an old challenge that doesn't specify its I/O format, I erred on the side of caution, taking input as a comma delimited string and outputting as a flattened array. Normally, though, yes, I'd have specified input as an array of strings, output as a multi-dimensional array and just used £ in place of the first 5 bytes. – Shaggy – 2019-07-19T20:49:09.240

    0

    Python 2, 90 bytes

    lambda s:sum((range(u[0],u[-1]+1)for u in[map(int,t.split('-'))for t in s.split(',')]),[])
    

    Try it online!

    Chas Brown

    Posted 2012-10-03T16:25:30.007

    Reputation: 8 959