Jimmy these arrays down

23

0

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.

James

Posted 2016-09-21T05:01:12.663

Reputation: 54 537

8

My apologies to Jimmy

– James – 2016-09-21T05:01:42.997

6Related. – DLosc – 2016-09-21T05:44:08.177

@DLosc Ah, that's what Jimmy is using in his pre-commit script! – Bergi – 2016-09-21T21:11:11.183

9Of course that Jimmy isn't a code golfer. – jimmy23013 – 2016-09-21T21:16:32.193

This challenge really rustled my Jimmies.

– DanTheMan – 2016-09-22T14:25:48.997

Answers

8

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

m-chrzan

Posted 2016-09-21T05:01:12.663

Reputation: 1 390

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. – James – 2016-09-21T06:48:27.737

Vim answers to standard [tag:code-golf] challenges should be scored in bytes.

– Martin Ender – 2016-09-21T06:49:36.037

Also, norm df= is shorter than s/.*=//g – James – 2016-09-21T06:49:41.490

1Also, 3wC] = {<esc> is shorter than <C-a>di]$s = {<esc>. – James – 2016-09-21T06:53:25.700

"vim ... proper text editor" does not compute – Geobits – 2016-09-21T21:19:44.517

1@Geobits Where's your Emacs answer? – Neil – 2016-09-22T00:27:02.203

@Neil Don't misunderstand me. I dislike both :P – Geobits – 2016-09-22T00:28:21.717

@Geobits Then what do you use? Notepad? – Neil – 2016-09-22T00:29:38.843

@Neil For code? No, I use a Proper Development Environment™ – Geobits – 2016-09-22T00:30:21.853

@Geobits Can your Proper Development Environment™, when applied to a 10-million-line codebase, still keep up with someone who types at 100wpm? If so, which one is it? (This is an entirely serious and non-sarcastic question. This is why I have never used a PDE™ for more than two minutes.) – zwol – 2016-09-22T15:01:10.263

@zwol I haven't worked on large codebases in many PDEs, but in my experience even Eclipse (I know, I know...) keeps up just fine if you turn off Intellisense. With it on, yeah... no. – Geobits – 2016-09-22T15:06:46.760

7

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.

Linus

Posted 2016-09-21T05:01:12.663

Reputation: 1 948

6

JavaScript (ES6), 65 64 63 bytes

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

Huntro

Posted 2016-09-21T05:01:12.663

Reputation: 459

5

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

Martin Ender

Posted 2016-09-21T05:01:12.663

Reputation: 184 808

5

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

nyro_0

Posted 2016-09-21T05:01:12.663

Reputation: 281

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. :)

– Kevin Cruijssen – 2016-09-21T09:08:33.393

1thanks 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 – nyro_0 – 2016-09-21T09:28:01.723

Using matchall would likely be shorter than splatting eachmatch. – Alex A. – 2016-09-22T19:51:11.917

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?) – nyro_0 – 2016-09-23T06:05:38.890

3

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

ATaco

Posted 2016-09-21T05:01:12.663

Reputation: 7 898

3

C, 121 bytes

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

orlp

Posted 2016-09-21T05:01:12.663

Reputation: 37 067

3

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.

Neil

Posted 2016-09-21T05:01:12.663

Reputation: 95 035

3

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};'

Caridorc

Posted 2016-09-21T05:01:12.663

Reputation: 2 254

At a quick look, I can see that there's an useless whitespace at [:-1] for. – Yytsi – 2016-09-22T07:03:22.153

2

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

Emigna

Posted 2016-09-21T05:01:12.663

Reputation: 50 798

žuDÀÀ instead of „[]„{} saves a byte :). – Adnan – 2016-09-21T06:51:32.937

@Adnan: Right, Good catch! – Emigna – 2016-09-21T06:54:19.117

2

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;"

Dada

Posted 2016-09-21T05:01:12.663

Reputation: 8 279

2

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

Kevin Cruijssen

Posted 2016-09-21T05:01:12.663

Reputation: 67 575

1few 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(".$","};");} – cliffroot – 2016-09-21T10:04:46.830

@cliffroot Thanks! Indeed some nice tricks like re-using the String in the parameter and replacing the last char with "};"); instead of an "")+"};";. – Kevin Cruijssen – 2016-09-21T10:19:50.567

1

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 “};”

Lynn

Posted 2016-09-21T05:01:12.663

Reputation: 55 648

1

sed 51

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

Riley

Posted 2016-09-21T05:01:12.663

Reputation: 11 345

1

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

Olivier Grégoire

Posted 2016-09-21T05:01:12.663

Reputation: 10 647

0

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 '=')

Jonathan Allan

Posted 2016-09-21T05:01:12.663

Reputation: 67 804

Down voter - what's wrong with it? – Jonathan Allan – 2016-09-22T21:21:18.047

0

Ruby, 64 bytes

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

cia_rana

Posted 2016-09-21T05:01:12.663

Reputation: 441

1Turns out that whitespace is required after all. – Martin Ender – 2016-09-21T13:48:38.413

0

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

James

Posted 2016-09-21T05:01:12.663

Reputation: 54 537

0

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)

mbomb007

Posted 2016-09-21T05:01:12.663

Reputation: 21 944

0

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!

Yytsi

Posted 2016-09-21T05:01:12.663

Reputation: 3 582