45
\$\begingroup\$

Related.

Given a printable ASCII string, split it into a list of non-empty strings with a new sub-string beginning every time a character, which has not previously been seen in the same case, occurs.

Examples

"mississippi" → ["m","i","ssissi","ppi"]

"P P & C G" → ["P"," P ","& ","C ","G"]

"AAA" → ["AAA"]

"Adam" → ["A","d","a","m"]

"" → []


Anecdote: The result will have between 0 and 95 elements. The 95th sub-string will necessarily continue until the end because at that point, all printable ASCII characters have begun a sub-string, so every additional character will have occurred before and thus cannot cause a new sub-string to begin.

\$\endgroup\$
  • 1
    \$\begingroup\$ An example containing " and ' seems like a good idea. \$\endgroup\$ – Emigna Feb 19 '18 at 18:15
  • \$\begingroup\$ Would ""[""] be acceptable? \$\endgroup\$ – Arnauld Feb 19 '18 at 18:18
  • 5
    \$\begingroup\$ @Emigna That just messes with the example output format without bringing any further clarity. \$\endgroup\$ – Adám Feb 19 '18 at 18:22
  • 1
    \$\begingroup\$ If outputting as a newline-separated string, can there be a leading/trailing newline? \$\endgroup\$ – wastl Feb 19 '18 at 21:32
  • 2
    \$\begingroup\$ @wastl Uh, I'll permit it in this case because it cannot indicate empty segments, although it does clash with my earlier ruling of [""] to be invalid. Sigh. \$\endgroup\$ – Adám Feb 19 '18 at 21:56

43 Answers 43

0
\$\begingroup\$

Javascript, 200 bytes

My first (I think?) attempt at code golf:

function split(s) {let x=[];let y=[];let z="";let w=1;for(l of s.split('')){if (x.includes(l)){z+=l;}else{w=!w;if (w) {y.push(z);z='';w=0;}z+=l;x.push(l);}}y.push(z);if (y.join('')==0) y=[];return y;}
\$\endgroup\$
  • 3
    \$\begingroup\$ You can remove almost all the spaces, no? \$\endgroup\$ – Adám Feb 19 '18 at 20:27
  • \$\begingroup\$ @Adám Ah, yes. Thanks for that tip. It's now 200 bytes. \$\endgroup\$ – aimorris Feb 19 '18 at 21:04
  • \$\begingroup\$ Ideas: one-letter function name, remove most remaining spaces, remove trailing semicolons: Try it online! \$\endgroup\$ – Adám Feb 19 '18 at 21:08
  • \$\begingroup\$ In general, this may help you. \$\endgroup\$ – Adám Feb 19 '18 at 21:14
  • 1
    \$\begingroup\$ I would also replace the if-else with a ternary operator. I know this is your first golfing attempt. I would recommend visiting Tips for golfing in JavaScript :) \$\endgroup\$ – Oliver Feb 19 '18 at 21:21
0
\$\begingroup\$

Mathematica, 84 bytes

a@{}={};a@b_:=a@b[[;;(c@b=Position[b,Tally[b][[-1,1]]][[1,1]])-1]]~Append~b[[c@b;;]]

Defines a function a. Takes a list of characters as input and returns a list of lists of characters as output. Uses a basic recursive structure.

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

Perl 5 + -p, 37 bytes

for$a(32..126){$a=chr$a;s/\Q$a/\n$a/}

Run through printable ASCII and insert a newline before the first appearance

Try it online!

\$\endgroup\$
  • \$\begingroup\$ For 30 (use a literal newline): eval";y/ -~/~ -}/;s/a/\na/"x95 \$\endgroup\$ – Ton Hospel Feb 20 '18 at 7:09
0
\$\begingroup\$

Retina 0.8.2, 22 20 19 bytes

1>`(.)(?<!\1.+)
¶$&

Try it online! Edit: Saved 2 3 bytes thanks to @MartinEnder.

\$\endgroup\$
  • \$\begingroup\$ @MartinEnder Ah yes, the lookahead was an artefact from a previous iteration that had to deal with overlapping matches, but I don't think I can use the non-word boundary because I need to be able to support all printable ASCII characters. \$\endgroup\$ – Neil Feb 20 '18 at 9:02
  • \$\begingroup\$ Oh, right, you can still use a limit though: tio.run/##K0otycxL/P/f0C5BQ09Tw95GMcZQT1uT69A2FbX//… \$\endgroup\$ – Martin Ender Feb 20 '18 at 9:06
0
\$\begingroup\$

Lua, 74 bytes

t={}print(((...):gsub(".",load"c=...a=(t[c]or'\\n')..c t[c]=''return a")))

Try it online!

Prints one additional leading newline.

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

GNU sed, 37 bytes

(includes +1 for -r option)

s/./\n&/g
:a
s/((.).*)\n\2/\1\2/
ta

We start by prepending a newline to every character in the string; then in the loop, we remove those that precede a second or subsequent occurrence.

Note that newline can't occur in the input, as that's the separator between strings. And it's not classified as a printable character.

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

C++, 176 bytes

#include<string>
#include<set>
std::string*s(std::string e){auto*r=new std::string[96];std::set<int>u;for(char p:e){if(u.find(p)==u.end())u.insert(p);r[u.size()]+=p;}return r;}

Returns an array of strings, valid strings member of the answer array are not of size 0.
Each call of the function allocate sizeof(std::string)*96, with the pointer returned, and must be delete[]d after usage. Code to test :

auto tests = {
    "mississippi","P P & C G", "AAA", "Adam",""
};

for (const auto& a : tests) {

    std::string* res = s(a);

    for (int i = 0; i < 96; ++i) {
        if (res[i].size() > 0)
            std::cout << '\"' << res[i] << "\", ";
    }

    delete[] res;
    std::cout << '\n';
}
\$\endgroup\$
  • \$\begingroup\$ Would it save bytes to use #define or using for std::string? \$\endgroup\$ – Zacharý Jul 18 '18 at 21:01
  • \$\begingroup\$ using S=std::string should save ~10 bytes. \$\endgroup\$ – Zacharý Nov 14 '18 at 13:24
  • \$\begingroup\$ Oh, in addition, auto can be changed to S as well. \$\endgroup\$ – Zacharý Nov 14 '18 at 14:16
0
\$\begingroup\$

AWK, 63 bytes

func u(v){for(;j++<split(v,A,"");)S[s]=S[s+=m[A[j]]++?0:1]A[j]}

Try it online!

Calling function u() assigns strings to string array S[] which is of size s

TIO link has some functionality in the footer to clear assigned variables.

Might be able to save a byte or two by using FS="", but this is a more general solution.

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

JavaScript, 105 87 bytes

Changes: replaced poop emojis for tabs (Thanks @Adám !), replaced parenthesis and aposthrophes for template literals

a=[];f=s=>s.split``.map(x=>!a.includes(x)&&a.push(x)?'  '+x:x).join``.split`    `.slice(1);

Takes a string, returns an array of strings. A big chunk is converting from String->[char]->String->[string]. whitout conversions, this becomes:

a=[];f=s=>s.map(x=>!a.includes(x)&&a.push(x)?'\n'+x:x).join``.slice(1);

takes char array, returns newline separated string (71 bytes).

Also, this is my first post on this stack exchange!

\$\endgroup\$
  • \$\begingroup\$ Welcome to the site and nice first post! This is actually 105 bytes in UTF-8, due to the emojis and we hope you'll continue to golf here! \$\endgroup\$ – caird coinheringaahing Mar 5 '18 at 21:55
  • \$\begingroup\$ Can't you use a literal tab instead of 💩︎ to save the extra bytes? \$\endgroup\$ – Adám Mar 5 '18 at 22:23
  • \$\begingroup\$ Ohh i thought poop emojis were 2 bytes long... Fixed \$\endgroup\$ – Sebastián Mestre Mar 5 '18 at 22:31
0
\$\begingroup\$

PowerShell, 61 bytes

$args|% t*y|%{if(!($r-cmatch"^[$_]")){$r+=,''};$r[-1]+=$_}
$r

Try it online!

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

Gema, 20 characters

?=${$1;\n}@set{$1;}?

Sample run:

bash-4.4$ gema '?=${$1;\n}@set{$1;}?' <<< 'mississippi'

m
i
ssissi
ppi

Try it online!

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

Clojure, 111 96 bytes

#(reverse(reduce(fn[[f & r :as R]i](if((set(apply str R))i)(cons(str f i)r)(cons(str i)R)))[]%))

As Jim Carrey would say: Beautiful! :D

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

Java 8, 159 bytes


134 bytes of lambda + 25 bytes for HashSet import. Rip all linters and IDEs.

import java.util.HashSet;
...
s->{HashSet h=new HashSet();return s.chars().mapToObj(c->(char)c+"").reduce("",(x,y)->x+(!h.isEmpty()&h.add(y)?","+y:y)).split(",");};

Try it online!

\$\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.