23
\$\begingroup\$

My coworker, Jimmy is kinda new to C/C++. He's also kind of a slow learner. Now, to be fair, his code always compiles, but he has some really sloppy habits. For example, everybody knows that you can define an array like this:

int spam[] = {4, 8, 15, 16, 23, 42};

Everybody that is, except for Jimmy. He is convinced that the only way to make an array is like this:

int spam[6];
spam[0] = 4;
spam[1] = 8;
spam[2] = 15;
spam[3] = 16;
spam[4] = 23;
spam[5] = 42;

I keep fixing this for him in code-review, but he won't learn. So I need you to write a tool that automagically does this for him when he commits¹.

The challenge

I want you to write either a full program or a function that takes in a multiline string as input, and outputs the more compact version of the C array. The input will always follow this format, whitespace included:

identifier_one identifier_two[some_length];
identifier_two[0] = some_number;
identifier_two[1] = some_number;
identifier_two[2] = some_number;
...
identifier_two[some_length - 1] = some_number;

In short, the input will always be valid and well defined C. In more detail:

All of the identifiers will be made up of just letters and underscores. The length will always be at least one, and there will never be any missing or out of bounds indexes. You may also assume that the indexes are in order. For example:

foo bar[3];
bar[0] = 1
bar[2] = 9;

foo bar[1];
bar[0] = 1;
bar[1] = 3;

and

foo bar[3];
bar[2] = 9;
bar[0] = 1
bar[1] = 3

are all invalid inputs, and may cause undefined behavior in your submission. You may also assume that all of the numbers will be valid decimal numbers, negative or positive. The input will not have extraneous spaces. The output should always follow this format, whitespace included:

identifier_one identifier_two[] = {n1, n2, n3, ...};

Here is some sample data:

Input:
spam eggs[10];
eggs[0] = 0;
eggs[1] = 4;
eggs[2] = 8;
eggs[3] = -3;
eggs[4] = 3;
eggs[5] = 7;
eggs[6] = 888;
eggs[7] = 555;
eggs[8] = 0;
eggs[9] = -2;

Output:
spam eggs[] = {0, 4, 8, -3, 3, 7, 888, 555, 0, -2};

Input:
char ans[2];
ans[0] = 52;
ans[1] = 50;

Output:
char ans[] = {52, 50};

Input:
blah_blah quux[1];
quux[0] = 105;

Output:
blah_blah quux[] = {105};

You may take your input and output in any reasonable format, such as STDIN/STDOUT, function arguments and return value, reading and writing files etc. Standard loopholes apply. The shortest answer in bytes wins!


¹This is passive-aggressive and a terrible idea. You did not get this idea from me.

\$\endgroup\$
  • 8
    \$\begingroup\$ My apologies to Jimmy \$\endgroup\$ – DJMcMayhem Sep 21 '16 at 5:01
  • 6
    \$\begingroup\$ Related. \$\endgroup\$ – DLosc Sep 21 '16 at 5:44
  • \$\begingroup\$ @DLosc Ah, that's what Jimmy is using in his pre-commit script! \$\endgroup\$ – Bergi Sep 21 '16 at 21:11
  • 9
    \$\begingroup\$ Of course that Jimmy isn't a code golfer. \$\endgroup\$ – jimmy23013 Sep 21 '16 at 21:16
  • \$\begingroup\$ This challenge really rustled my Jimmies. \$\endgroup\$ – DanTheMan Sep 22 '16 at 14:25

20 Answers 20

8
\$\begingroup\$

Vim, 43 36 bytes

You don't need to give Jimmy a script, just teach him to use a proper text editor. (literal returns for clarity)

:%s/.*=//|%s/;\n/,/<cr><cr>
3wcf ] = {<esc>
$s};
\$\endgroup\$
  • \$\begingroup\$ Nice! In this specific instance, <C-a> is shorter than t], which is a fun little hack. Also, I think you technically need 2 <cr> since it asks for confirmation. \$\endgroup\$ – DJMcMayhem Sep 21 '16 at 6:48
  • \$\begingroup\$ Vim answers to standard code-golf challenges should be scored in bytes. \$\endgroup\$ – Martin Ender Sep 21 '16 at 6:49
  • \$\begingroup\$ Also, norm df= is shorter than s/.*=//g \$\endgroup\$ – DJMcMayhem Sep 21 '16 at 6:49
  • 1
    \$\begingroup\$ Also, 3wC] = {<esc> is shorter than <C-a>di]$s = {<esc>. \$\endgroup\$ – DJMcMayhem Sep 21 '16 at 6:53
  • 1
    \$\begingroup\$ @Geobits Where's your Emacs answer? \$\endgroup\$ – Neil Sep 22 '16 at 0:27
7
\$\begingroup\$

CJam, 43 36 bytes

qN/('[/~;"[] = {"@{S/W=W<}%", "*"};"

Online Example

Explanation:

qN/                                     |Read all lines to array
   ('[/~;                               |slice first line left of [
         "[] = {"                       |add formatting to stack
                 @                      |rotate to remaining lines
                  {      }%             |for each line in array
                   S/W=                 |split after last space
                       W<               |remove last character (;)
                           ", "*        |insert ", " to array
                                "};"    |add formatting

A big thanks to Martin Ender for the improvements on my first CJam answer.

\$\endgroup\$
6
\$\begingroup\$

JavaScript (ES6), 65 64 63 bytes

s=>`${s.split`[`[0]}[] = {${s.match(/-?\d+(?=;)/g).join`, `}};`
\$\endgroup\$
5
\$\begingroup\$

Retina, 30 28 bytes

Byte count assumes ISO 8859-1 encoding.

\d+];¶.+ 
] = {
;¶.+=
,
;
};

Try it online!

Explanation

We'll use the following input as an example:

spam eggs[4];
eggs[0] = 0;
eggs[1] = 4;
eggs[2] = 8;
eggs[3] = -3;

Stage 1

\d+];¶.+ 
] = {

Note that there's a trailing space on the first line.

We start by matching a number following by ]; and a linefeed, and then everything up to the last space on the next line. This match can only be found at the end of the first line (due to the ];). All of this is replaced with ] = {. That is, it transforms our example input to:

spam eggs[] = {0;
eggs[1] = 4;
eggs[2] = 8;
eggs[3] = -3;

Stage 2

;¶.+=
,

Now we match everything from a ; up to the = on the next line and replace with a ,. This transforms the string to:

spam eggs[] = {0, 4, 8, -3;

Stage 3

;
};

All that's left is fixing the end and we do this by replacing the only remaining ; with };:

spam eggs[] = {0, 4, 8, -3};
\$\endgroup\$
5
\$\begingroup\$

Julia, 112 108 105 Bytes

f(s)=string(split(s,'[')[1],"[] = {",join([m[1] for m in [eachmatch(r"= *(-?\d+)",s)...]],", "),"};")

Explanation

string(                                                         # build output string
split(s,'[')[1],                                                # get declaration (e.g. spam eggs)
"[] = {",                                                       # add [] = {
join(                                                           # collect numbers
    [m[1] for m in [eachmatch(r"= *(-?\d+)",s)...]],            # regex out (signed) numbers
    ", "),                                                      # and join comma separated
"};"                                                            # add };
)                                                               # close string(

Saved bytes by replacing collect(eachmatch()) with [eachmatch()...] and with a shorter regex

\$\endgroup\$
  • \$\begingroup\$ Hi, welcome to PPCG! This looks like a great first answer. +1 from me. Since the challenge states "You may take your input and output in any reasonable format", you can remove the space after the comma separator in the eachmatch function-call for a less pretty output and -1 byte. I never programmed in Julia myself, but you might find this post interesting to read: Tips for golfing in Julia. Again welcome, and enjoy your stay. :) \$\endgroup\$ – Kevin Cruijssen Sep 21 '16 at 9:08
  • 1
    \$\begingroup\$ thanks very much for your kind words :) PPCG seemed to be fun to look into, so I thought I'll give it a try. Chose Julia for this answer as it wasn't present yet \$\endgroup\$ – nyro_0 Sep 21 '16 at 9:28
  • \$\begingroup\$ Using matchall would likely be shorter than splatting eachmatch. \$\endgroup\$ – Alex A. Sep 22 '16 at 19:51
  • \$\begingroup\$ i tried using matchall first, but it doesn'lt let me use regex groups (the part in the parenthesis what I am particularly interested in) as opposed to eachmatch. (or I just couldn't find it in the documentation?) \$\endgroup\$ – nyro_0 Sep 23 '16 at 6:05
3
\$\begingroup\$

Lua, 121 Bytes.

function g(s)print(s:gmatch('.-%[')()..'] = {'..s:gsub('.-\n','',1):gsub('.-([%d.-]+);\n?','%1, '):gsub(',%s+$','};'))end

Explained

function g(s)
    print(                              -- Print, Self Explaintry.
        s:gmatch('.-%[')()..'] = {'     -- Find the 'header', match the first line's class and assignment name (everything up to the 'n]') and append that. Then, append ] = {.
                                        -- In the eggs example, this looks like; 'spam eggs[] = {' now
        ..                              -- concatenate...
        s:gsub('.-\n','',1)             -- the input, with the first line removed.
        :gsub('.-([%d.-]+);\n?','%1, ') -- Then that chunk is searched, quite boringly, a number followed by a semicolon, and the entire string is replaced with an array of those,
                                        -- EG, '1, 2, 3, 4, 5, 6, '
        :gsub(',%s+$','};')          -- Replace the final ', ' (if any) with a single '};', finishing our terrifying combination
    )
end
\$\endgroup\$
3
\$\begingroup\$

Batch, 160 bytes

@echo off
set/ps=
set s=%s:[=[] = {&rem %
set r=
:l
set t=
set/pt=
if "%t%"=="" echo %r%};&exit/b
set t=%t:* =%
set r=%r%%s%%t:~2,-1%
set s=, 
goto l

Note: The line set s=, ends with a space. Takes input on STDIN. That weird line 3 takes the input (e.g. int spam[6]; and changes the [ into [] = {&rem resulting in set s=int spam[] = {&rem 6]; which then gets interpreted as two statements, set s=int spam[] = { and rem 6];, the latter of which is a comment. Then for each line we delete the text up to the first space (because you can't use = in a pattern and the matching is non-greedy) and extract the value.

\$\endgroup\$
3
\$\begingroup\$

C, 121 bytes

n=2;main(i){for(;putchar(getchar())^91;);for(printf("] = {");~scanf("%*[^=]%*c%d",&i);n=0)printf(", %d"+n,i);puts("};");}
\$\endgroup\$
3
\$\begingroup\$

Python 112 111

Very straightforward to me, please suggest any improvement that comes to mind.

def f(l):
 a,*b=l.split('\n')
 return a[:a.index('[')]+'[] = {'+', '.join(r.split(' = ')[1][:-1]for r in b)+'};'


# TEST

lines = """spam eggs[10];
eggs[0] = 0;
eggs[1] = 4;
eggs[2] = 8;
eggs[3] = -3;
eggs[4] = 3;
eggs[5] = 7;
eggs[6] = 888;
eggs[7] = 555;
eggs[8] = 0;
eggs[9] = -2;"""
print (f(lines))
assert f(lines) == 'spam eggs[] = {0, 4, 8, -3, 3, 7, 888, 555, 0, -2};'
\$\endgroup\$
  • \$\begingroup\$ At a quick look, I can see that there's an useless whitespace at [:-1] for. \$\endgroup\$ – Yytsi Sep 22 '16 at 7:03
2
\$\begingroup\$

05AB1E, 31 30 28 bytes

žh-|vy#¤¨ˆ\}¨… = ¯ïžuDÀÀ‡';J

Explanation

žh-¨                            # remove numbers and ";" from first input
    |v      }                   # for each of the rest of the inputs
      y#                        # split on spaces
        ¤¨                      # take the last element (number) minus the last char (";") 
          ˆ\                    # store in global array and throw the rest of the list away
             … =                # push the string " = "
                 ¯ï             # push global array and convert to int
                   žuDÀÀ‡       # replace square brackets of array with curly ones
                         ';     # push ";"
                           J    # join everything and display

Try it online!

Saved a byte thanks to Adnan

\$\endgroup\$
  • \$\begingroup\$ žuDÀÀ instead of „[]„{} saves a byte :). \$\endgroup\$ – Adnan Sep 21 '16 at 6:51
  • \$\begingroup\$ @Adnan: Right, Good catch! \$\endgroup\$ – Emigna Sep 21 '16 at 6:54
2
\$\begingroup\$

Java 7, 159 158 149 154 bytes

String c(String[]a){a[0]=a[0].split("\\d")[0]+"] = {\b";for(String i:a)a[0]+=i.split("= [{]*")[1];return a[0].replace(";",", ").replaceFirst("..$","};");}

Multiple bytes saved thanks to @cliffroot.

Ungolfed & test code:

Try it here.

class M{
  static String c(String[] a){
    a[0] = a[0].split("\\d")[0] + "] = {\b";
    for(String i : a){
      a[0] += i.split("= [{]*")[1];
    }
    return a[0].replace(";", ", ").replaceFirst("..$", "};");
  }

  public static void main(String[] a){
    System.out.println(c(new String[]{ "spam eggs[10];", "eggs[0] = 0;", "eggs[1] = 4;",
      "eggs[2] = 8;", "eggs[3] = -3;", "eggs[4] = 3;", "eggs[5] = 7;", "eggs[6] = 888;",
      "eggs[7] = 555;", "eggs[8] = 0;", "eggs[9] = -2;" }));
    System.out.println(c(new String[]{ "char ans[2]", "ans[0] = 52;", "ans[1] = 50;" }));
    System.out.println(c(new String[]{ "blah_blah quux[1];", "quux[0] = 105;" }));
  }
}

Output:

spam eggs[] = {0, 4, 8, -3, 3, 7, 888, 555, 0, -2};
char ans[] = {52, 50};
blah_blah quux[] = {105};
\$\endgroup\$
  • 1
    \$\begingroup\$ few bytes saved String c(String[]a){a[0]=a[0].split("\\d")[0]+"]={ \b";for(String i:a)a[0]+=i.split("=[{]*")[1];return a[0].replace(';',',').replaceFirst(".$","};");} \$\endgroup\$ – cliffroot Sep 21 '16 at 10:04
  • \$\begingroup\$ @cliffroot Thanks! Indeed some nice tricks like re-using the String in the parameter and replacing the last char with "};"); instead of an "")+"};";. \$\endgroup\$ – Kevin Cruijssen Sep 21 '16 at 10:19
2
\$\begingroup\$

Perl, 42 + 2 (-0p) = 44 bytes

s%\d+].*%] = {@{[join",",/(-?\d+);/g]}};%s

Needs -p and -0 flags to run. For instance :

perl -0pe 's%\d+].*%] = {@{[join",",/(-?\d+);/g]}};%s' <<< "blah_blah quux[1];
quux[0] = 105;"
\$\endgroup\$
1
\$\begingroup\$

Jelly, 27 bytes

Ỵ©ḢḟØDṖ“ = {”®Ḳ€Ṫ€Ṗ€j⁾, ⁾};

Try it online!

Explanation

Ỵ         Split into lines
 ©Ḣ       Take the first one, store the others in ®
   ḟØD    Remove digits
      Ṗ   Remove trailing ;

“ = {”    Print a literal string

®         Recall the remaining lines
 Ḳ€       Split each into words
   Ṫ€     Keep each last word
     Ṗ€   Remove each trailing ;

j⁾,       Join by “, ”
    ⁾};   Literal “};”
\$\endgroup\$
1
\$\begingroup\$

sed 51

1s,\[.*,[] = {,
:
N
s,\n.*= ,,
s/;/, /
$s/, $/};/
t
\$\endgroup\$
1
\$\begingroup\$

Java, 106 bytes

String manipulation in Java is hell, as always.

a->a[0].join("",a).replaceAll(";\\w+\\[\\d+\\] = ",", ").replaceAll("\\d+\\], ","] = {").replace(";","};")

This is a pure regex answer. Make a single concatenated String, then perform replaceXxx until it's ok.

Testing and ungolfed:

import java.util.function.Function;

public class Main {

  public static void main(String[] args) {
    Function<String[], String> f = a ->
        String.join("", a)                          // I think this would join. Not sure, though. Golfed into a[0].join because static members are accessible from instances.
            .replaceAll(";\\w+\\[\\d+\\] = ", ", ") // replace with regex
            .replaceAll("\\d+\\], ", "] = {")       // replace with regex
            .replace(";", "};");                    // replace no regex

    String[] spam = {
      "int spam[6];",
      "spam[0] = 4;",
      "spam[1] = 8;",
      "spam[2] = 15;",
      "spam[3] = 16;",
      "spam[4] = 23;",
      "spam[5] = 42;"
    };
    test(f, spam, "int spam[] = {4, 8, 15, 16, 23, 42};");

    String[] eggs = {
      "spam eggs[10];",
      "eggs[0] = 0;",
      "eggs[1] = 4;",
      "eggs[2] = 8;",
      "eggs[3] = -3;",
      "eggs[4] = 3;",
      "eggs[5] = 7;",
      "eggs[6] = 888;",
      "eggs[7] = 555;",
      "eggs[8] = 0;",
      "eggs[9] = -2;"
    };
    test(f, eggs, "spam eggs[] = {0, 4, 8, -3, 3, 7, 888, 555, 0, -2};");

    String[] ans = {
      "char ans[2];",
      "ans[0] = 52;",
      "ans[1] = 50;"
    };
    test(f, ans, "char ans[] = {52, 50};");

    String[] quux = {
      "blah_blah quux[1];",
      "quux[0] = 105;"
    };
    test(f, quux, "blah_blah quux[] = {105};");

  }

  static void test(Function<String[], String> f, String[] input, String expected) {
    System.out.printf("Result:   %s%nExpected: %s%n", f.apply(input), expected);
  }
}
\$\endgroup\$
0
\$\begingroup\$

Jelly, 33 bytes

ỴḊḲ€Ṫ€K⁾;,yṖ“{“};”j
ỴḢḟØDṖ,⁾ =,ÇK

TryItOnline

How?

ỴḊḲ€Ṫ€K⁾;,yṖ“{“};”j - Link 1, parse and reform the values, same input as the Main link
Ỵ                   - split on line feeds
 Ḋ                  - dequeue (remove the first line)
  Ḳ€                - split each on spaces
    Ṫ€              - tail each (get the numbers with trailing ';')
      K             - join on spaces
       ⁾;,          - ";,"
          y         - map (replace ';' with ',')
           Ṗ        - pop (remove the last ',')
            “{“};”  - list of strings ["{","};"]
                  j - join (making "{" + "n0, n1, ,n2, ..." + "};")

ỴḢḟØDṖ,⁾ =,ÇK - Main link, takes one argument, the multiline string
Ỵ             - split on line feeds
 Ḣ            - head (just the first line)
   ØD         - digits yield "0123456789"
  ḟ           - filter out
     Ṗ        - pop (remove the trailing ';')
      ,   ,   - pair
       ⁾ =    - the string " ="
           Ç  - call the previous Link (1)
            K - join on spaces (add the space after the '=')
\$\endgroup\$
  • \$\begingroup\$ Down voter - what's wrong with it? \$\endgroup\$ – Jonathan Allan Sep 22 '16 at 21:21
0
\$\begingroup\$

Ruby, 64 bytes

->{gets.split(?[)[0]+"[]={"+$<.map{|s|s.scan /\ -?\d+/}*?,+"};"}
\$\endgroup\$
0
\$\begingroup\$

JavaScript, 125 bytes

I know it's longer than others, but I really wanted to use eval. Just for fun.

f=function(s){m=/^(\w+ )(\w+).*?(;.*)/.exec(s)
eval("var "+m[2]+"=new Array()"+m[3]+'alert(m[1]+m[2]+"={"+eval(m[2])+"};")')}

To run, paste the following into here:

s='int spam[6];\
spam[0] = 4;\
spam[1] = 8;\
spam[2] = 15;\
spam[3] = 16;\
spam[4] = 23;\
spam[5] = 42;'
f=function(s){m=/^(\w+ )(\w+).*?(;.*)/.exec(s)
eval("var "+m[2]+"=new Array()"+m[3]+'alert(m[1]+m[2]+"={"+eval(m[2])+"};")')}
f(s)
\$\endgroup\$
0
\$\begingroup\$

Haxe, 234 bytes

function R(L:Array<String>){var S=L[0];var W=S.indexOf(" ");var T=S.substr(0,W),M=S.substring(W+1,S.indexOf("["));var r=[for(i in 1...L.length)L[i].substring(L[i].lastIndexOf(" ")+1,L[i].length-1)].join(', ');return'$T $M[] = {$r};';}

Long function names killed this :D

Try the testcases here!

\$\endgroup\$
0
\$\begingroup\$

V, 25, 24 bytes

3wC] = {òJd2f $s, òhC};

Try it online! This contains an unprintable <esc> character, so here is a hexdump:

0000000: 3377 435d 203d 207b 1bf2 4a64 3266 2024  3wC] = {..Jd2f $
0000010: 732c 20f2 6843 7d3b                      s, .hC};

Explanation:

3w                              "Move forward 3 words
  C     <esc>                   "Delete everything until the end of the line, and enter this text:
   ] = {                        "'] = {'
             ò         ò        "Recursively:
              J                 "  Join these two lines (which enters a space)
               d                "  Delete everything until you
                2f              "  (f)ind the (2)nd space
                   $            "  Move to the end of this line
                    s           "  Delete a character, and enter:
                     ,          "  ', '
                                "
                        h       "Move one character to the left
                         C      "Delete everything until the end of the line, and enter this text:
                          };    "'};'
\$\endgroup\$

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.