51
\$\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\$
19
  • 1
    \$\begingroup\$ An example containing " and ' seems like a good idea. \$\endgroup\$
    – Emigna
    Commented Feb 19, 2018 at 18:15
  • \$\begingroup\$ Would ""[""] be acceptable? \$\endgroup\$
    – Arnauld
    Commented Feb 19, 2018 at 18:18
  • 5
    \$\begingroup\$ @Emigna That just messes with the example output format without bringing any further clarity. \$\endgroup\$
    – Adám
    Commented Feb 19, 2018 at 18:22
  • 1
    \$\begingroup\$ If outputting as a newline-separated string, can there be a leading/trailing newline? \$\endgroup\$
    – wastl
    Commented Feb 19, 2018 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
    Commented Feb 19, 2018 at 21:56

55 Answers 55

1
2
1
\$\begingroup\$

Red, 79 bytes

func[s][foreach c next unique/case append s"^@"[print copy/part s s: find s c]]

Try it online!

Ungolfed:

f: func [s] [
    b: next unique/case append s "^@"  ; append `null` to the end of the string, than
                                       ; find the unique characters and 
                                       ; store all except the first to b  
    foreach c b [                      ; for each character in b
        print copy/part s s: find s c  ; print the part of the string to
                                       ; where the character is found and
                                       ; set the beginning of the string to that position
    ]
] 
\$\endgroup\$
1
\$\begingroup\$

Retina 0.8.2, 22 20 19 bytes

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

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

\$\endgroup\$
2
  • \$\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
    Commented Feb 20, 2018 at 9:02
  • \$\begingroup\$ Oh, right, you can still use a limit though: tio.run/##K0otycxL/P/f0C5BQ09Tw95GMcZQT1uT69A2FbX//… \$\endgroup\$ Commented Feb 20, 2018 at 9:06
1
\$\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\$
1
\$\begingroup\$

SNOBOL4 (CSNOBOL4), 115 91 77 bytes

	N =INPUT
S	N LEN(1) . Y	:F(END)
	S =S Y
	N SPAN(S) . OUTPUT REM . N	:(S)
END

Try it online!

Prints the substrings separated by newlines.

Explanation:

line S (for SPLIT) doesn't actually split, but instead extracts the first character of N and saves it (.) to Y. On Failure, it jumps to END. The match should only fail when N is the empty string. Thus, when the input is empty, it jumps directly to END and outputs nothing.

S = S Y concatenates Y onto S.

SPAN(S) greedily matches a run of characters in S, and sends it (.) to OUTPUT, setting (.) N to the REMaining characters of N (if there are any). Then it jumps back to S.

\$\endgroup\$
1
\$\begingroup\$

PowerShell, 73 bytes

{$r=@();$h=@{};[char[]]$ARGS[0]|%{if(!($h[$_]++)){$r+=""};$r[-1]+=$_};$r}

Usage

PS> & {$r=@();$h=@{};[char[]]$ARGS[0]|%{if(!($h[$_]++)){$r+=""};$r[-1]+=$_};$r} "mississipi" | ConvertTo-Json -Compress
["m","i","ssissi","pi"]
\$\endgroup\$
1
  • \$\begingroup\$ you can save some bytes - Try it online! \$\endgroup\$
    – mazzy
    Commented Mar 8, 2019 at 4:51
1
\$\begingroup\$

Ruby, 65 62 58 bytes

->s,*a{s.size.times{|i|(i==s.index(c=s[i])?a:a[-1])<<c}
a}

Try it online!

A lambda accepting a string and returning an array of strings.

Approach: For each index, either append the character at that index in s to the result array, or to the last string in the result array. String#index returns the index of the first instance of the argument.

-2 bytes: Initialize a as a splat argument instead of on its own line. Thanks, Value Ink!

-1 byte: Use c=s[i]...c instead of s[i]...s[i]. Thanks, Value Ink!

-4 bytes: Use .times instead of .map

\$\endgroup\$
1
1
\$\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\$
1
\$\begingroup\$

Ruby, 40 bytes

->a{i=0
a.slice_when{a.index(_2)==i+=1}}

Attempt This Online!

\$\endgroup\$
7
  • \$\begingroup\$ This isn't reusable - $. isn't reset on every iteration, and it might not be set to 0 if the user uses gets or $<. \$\endgroup\$
    – naffetS
    Commented Oct 20, 2022 at 18:11
  • \$\begingroup\$ @Sʨɠɠan That’s correct. \$\endgroup\$
    – Jordan
    Commented Oct 20, 2022 at 18:18
  • \$\begingroup\$ What I mean is that this is currently invalid: codegolf.meta.stackexchange.com/a/4940/92689 \$\endgroup\$
    – naffetS
    Commented Oct 20, 2022 at 18:23
  • 1
    \$\begingroup\$ Yes. codegolf.meta.stackexchange.com/a/10753/92689 Ruby's enumerator is basically Python's version of a generator, so it applies. \$\endgroup\$
    – naffetS
    Commented Oct 20, 2022 at 18:29
  • 1
    \$\begingroup\$ @Sʨɠɠan Thanks. I've updated my answer. \$\endgroup\$
    – Jordan
    Commented Oct 20, 2022 at 18:31
1
\$\begingroup\$

Uiua SBCS, 6 bytes

⊜□\+◰.

Try it!

⊜□\+◰.
     .  # duplicate
    ◰   # mark firsts
  \+    # cumulative sum
⊜□      # split
\$\endgroup\$
1
\$\begingroup\$

APL (Dyalog APL), 3 bytes

≠⊂⊢

Attempt This Online!

 the Boolean mask indicating first occurrence of each character…

 splits…

 the argument

\$\endgroup\$
1
\$\begingroup\$

Vyxal, 5 bytes

ÞUÞṗḢ

Try it Online!

  Þṗ  # Partition before
ÞU    # Uniquity mask
    Ḣ # Remove leading empty list
\$\endgroup\$
1
\$\begingroup\$

Scala 3, 109 bytes

_.foldLeft(Seq.empty)((l,c)=>if(l.exists(_.contains(c)))l.dropRight(1):+l.last.appended(c)else l:+c.toString)

Attempt This Online!

\$\endgroup\$
1
\$\begingroup\$

Arturo, 42 bytes

$=>[0s:[]chunk&'c[if¬in? c,s->+1's++c<=]]

Try it!

\$\endgroup\$
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\$
7
  • 3
    \$\begingroup\$ You can remove almost all the spaces, no? \$\endgroup\$
    – Adám
    Commented Feb 19, 2018 at 20:27
  • \$\begingroup\$ @Adám Ah, yes. Thanks for that tip. It's now 200 bytes. \$\endgroup\$
    – aimorris
    Commented Feb 19, 2018 at 21:04
  • \$\begingroup\$ Ideas: one-letter function name, remove most remaining spaces, remove trailing semicolons: Try it online! \$\endgroup\$
    – Adám
    Commented Feb 19, 2018 at 21:08
  • \$\begingroup\$ In general, this may help you. \$\endgroup\$
    – Adám
    Commented Feb 19, 2018 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
    Commented Feb 19, 2018 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\$
1
  • \$\begingroup\$ For 30 (use a literal newline): eval";y/ -~/~ -}/;s/a/\na/"x95 \$\endgroup\$
    – Ton Hospel
    Commented Feb 20, 2018 at 7:09
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\$

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\$
3
  • \$\begingroup\$ Would it save bytes to use #define or using for std::string? \$\endgroup\$
    – Adalynn
    Commented Jul 18, 2018 at 21:01
  • \$\begingroup\$ using S=std::string should save ~10 bytes. \$\endgroup\$
    – Adalynn
    Commented Nov 14, 2018 at 13:24
  • \$\begingroup\$ Oh, in addition, auto can be changed to S as well. \$\endgroup\$
    – Adalynn
    Commented Nov 14, 2018 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\$
3
  • \$\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\$ Commented Mar 5, 2018 at 21:55
  • \$\begingroup\$ Can't you use a literal tab instead of 💩︎ to save the extra bytes? \$\endgroup\$
    – Adám
    Commented Mar 5, 2018 at 22:23
  • \$\begingroup\$ Ohh i thought poop emojis were 2 bytes long... Fixed \$\endgroup\$ Commented Mar 5, 2018 at 22:31
0
\$\begingroup\$

PowerShell, 61 bytes

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

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\$
0
\$\begingroup\$

Japt, 8 bytes

ò@bY ¶°T

Try it

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

JavaScript (Node.js), 31 bytes

x=>x.match(/.((.)(?<=\2.+))*/g)

Try it online!

Pure regex

\$\endgroup\$
1
2

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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