50
\$\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
    Feb 19, 2018 at 18:15
  • \$\begingroup\$ Would ""[""] be acceptable? \$\endgroup\$
    – Arnauld
    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
    Feb 19, 2018 at 18:22
  • 1
    \$\begingroup\$ If outputting as a newline-separated string, can there be a leading/trailing newline? \$\endgroup\$
    – wastl
    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
    Feb 19, 2018 at 21:56

50 Answers 50

1
2
1
\$\begingroup\$

Java 8, 193 169 155 151 bytes

s->{for(int l=s.length(),i=0,j;i<l;i++)if(s.indexOf(s.charAt(i))==i){for(j=i;++j<l&&s.indexOf(s.charAt(j))!=j;);System.out.println(s.substring(i,j));}}

-14 bytes thanks to @raznagul (for something obvious I somehow missed myself..)
-3 bytes thanks to @O.O.Balance (again for something obvious I somehow missed myself.. :S)

Explanation:

Try it online.

s->{                    // Method with String parameter and no return-type
  for(int l=s.length(), //  The length of the input-String
          i=0,j;        //  Index integers
      i<l;i++)          //  Loop `i` from 0 to `l` (exclusive)
    if(s.indexOf(s.charAt(i))==i){
                        //   If the character at index `i` hasn't occurred yet:
      for(j=i;++j<l     //    Inner loop `j` from `i` to `l` (exclusive),
          &&s.indexOf(s.charAt(j))!=j;);
                        //     as long as the character at index `j` has already occurred
      System.out.println(//    Print:
        s.substring(i,j));}}
                        //     The substring of the input from index `i` to `j` (exclusive)
\$\endgroup\$
4
  • 1
    \$\begingroup\$ I don't think you need the if(l<1). If l is 0 the loop shouldn't be executed anyway as 0<0 is false. \$\endgroup\$
    – raznagul
    Feb 20, 2018 at 14:46
  • \$\begingroup\$ @raznagul Not sure how I missed that, but you're complete right!.. >.> \$\endgroup\$ Feb 20, 2018 at 14:56
  • \$\begingroup\$ You're setting i=0 twice. You can save 3 bytes by dropping the second one: for(;i<l;i++) \$\endgroup\$ Jul 18, 2018 at 19:27
  • \$\begingroup\$ @O.O.Balance Not sure how that happened.. :S But thanks for noticing! :) \$\endgroup\$ Jul 19, 2018 at 8:23
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
    Oct 20, 2022 at 18:11
  • \$\begingroup\$ @Sʨɠɠan That’s correct. \$\endgroup\$
    – Jordan
    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
    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
    Oct 20, 2022 at 18:29
  • 1
    \$\begingroup\$ @Sʨɠɠan Thanks. I've updated my answer. \$\endgroup\$
    – Jordan
    Oct 20, 2022 at 18:31
1
\$\begingroup\$

Perl 5 + -pl, 22 bytes

s@.@$/x!$h{$&}++.$&@ge

Try it online!

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

APL (Dyalog APL), 3 bytes

≠⊂⊢

Attempt This Online!

 the Boolean mask indicating first occurrence of each character…

 splits…

 the argument

\$\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
    Feb 19, 2018 at 20:27
  • \$\begingroup\$ @Adám Ah, yes. Thanks for that tip. It's now 200 bytes. \$\endgroup\$
    – aimorris
    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
    Feb 19, 2018 at 21:08
  • \$\begingroup\$ In general, this may help you. \$\endgroup\$
    – Adám
    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
    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
    Feb 20, 2018 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\$
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
    Feb 20, 2018 at 9:02
  • \$\begingroup\$ Oh, right, you can still use a limit though: tio.run/##K0otycxL/P/f0C5BQ09Tw95GMcZQT1uT69A2FbX//… \$\endgroup\$ Feb 20, 2018 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\$
3
  • \$\begingroup\$ Would it save bytes to use #define or using for std::string? \$\endgroup\$
    – Adalynn
    Jul 18, 2018 at 21:01
  • \$\begingroup\$ using S=std::string should save ~10 bytes. \$\endgroup\$
    – Adalynn
    Nov 14, 2018 at 13:24
  • \$\begingroup\$ Oh, in addition, auto can be changed to S as well. \$\endgroup\$
    – Adalynn
    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\$ Mar 5, 2018 at 21:55
  • \$\begingroup\$ Can't you use a literal tab instead of 💩︎ to save the extra bytes? \$\endgroup\$
    – Adám
    Mar 5, 2018 at 22:23
  • \$\begingroup\$ Ohh i thought poop emojis were 2 bytes long... Fixed \$\endgroup\$ 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\$

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

Uiua SBCS, 6 bytes

⊜□\+◰.

Try it!

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

Vyxal, 5 bytes

ÞUÞṗḢ

Try it Online!

  Þṗ  # Partition before
ÞU    # Uniquity mask
    Ḣ # Remove leading empty list
\$\endgroup\$
0
\$\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
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.