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

24
\$\begingroup\$

Jelly, 4 bytes

QƤĠị

Try it online!

Explanation

QƤĠị  Input is a string, say s = "adam"
 Ƥ    For each prefix of s: ["a","ad","ada","adam"]
Q     remove duplicates: ["a","ad","ad","adm"]
  Ġ   Group indices by equal values: [[1],[2,3],[4]]
   ị  Index into s: ["a","da","m"]

The internal representation of the strings, which the TIO link displays, is slightly different.

\$\endgroup\$
4
  • \$\begingroup\$ Can someone explain the logic of this solution? I can see that it does work, but I can't get my head around why it works; like, I wouldn't have thought that indexing back into the original string where the deduped prefixes match would yield the answer. \$\endgroup\$
    – Aaron
    Feb 27 at 5:55
  • \$\begingroup\$ The list p of nonempty prefixes of s has the same length as s. For each index i, the string p[i] is the prefix of s up to and including s[i]. Two adjacent chars s[i] and s[i+1] should be in the same chunk in the output if s[i+1] already occurred before index i, or in other words, in the prefix p[i]. This is equivalent to p[i] and p[i+1] having the same set of unique characters. I compute with the unique characters of each prefix p[i]. \$\endgroup\$
    – Zgarb
    Feb 29 at 11:17
  • \$\begingroup\$ @Aaron Then with Ġ I group the indices i of this list of strings: indices i and i+1 go in the same chunk if p[i] and p[i+1] have the same unique characters. Finally, with I index back to the original string s, essentially grouping it into chunks in the same way as the indices i. \$\endgroup\$
    – Zgarb
    Feb 29 at 11:18
  • \$\begingroup\$ Thank you, that's starting to make a bit more sense for me. Impressive answer! \$\endgroup\$
    – Aaron
    Feb 29 at 19:51
10
\$\begingroup\$

Retina, 9 bytes

q1,`.
¶$&

Try it online!

Explanation

Match each character (.), discard repeated matches (q), discard the first match (1,), and insert a linefeed in front of each match ¶$&.

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

05AB1E, 11 bytes

ÙSk¥sg¸«£õK

Try it online!

Explanation

Ù             # remove duplicates in input
 S            # split to a list of characters
  k           # get the (first) index of each character in the input
   ¥          # calculate delta's
    sg¸«      # append the length of the input
        £     # split the list into pieces of these sizes
         õK   # remove empty string (for the special case "" -> [])
\$\endgroup\$
1
  • 1
    \$\begingroup\$ For anyone coming across this answer, ¸« can be ª in the new version of 05AB1E. \$\endgroup\$ Mar 8, 2019 at 12:43
6
\$\begingroup\$

J, 7 bytes

~:<;.1]

Try it online!

Explanation

Nub sieve's chance to shine!

~: <;.1 ]
        ]  Input
~:         Nub sieve (1 if the character is the first instance in string)
    ;.1    Split input on 1s in nub sieve
   <       And box each
\$\endgroup\$
2
  • 2
    \$\begingroup\$ I was about to post exactly the same (not surprisingly) answer, it's good that I glanced your submission before that :) \$\endgroup\$ Feb 19, 2018 at 19:48
  • 2
    \$\begingroup\$ @GalenIvanov I -- and I imagine most other J golfers, too -- relish the chance to use nub sieve or self-classify. \$\endgroup\$
    – cole
    Feb 19, 2018 at 20:18
6
\$\begingroup\$

APL (Dyalog Unicode), 8 bytesSBCS

(≢¨∪\)⊆⊢

Try it online!

\$\endgroup\$
4
  • \$\begingroup\$ But, but… Oh my. \$\endgroup\$
    – Adám
    Feb 20, 2018 at 18:06
  • \$\begingroup\$ I suspected you might have posted this challenge because of the new primitive (⊆). Evidently not :) \$\endgroup\$
    – ngn
    Feb 20, 2018 at 20:15
  • \$\begingroup\$ It looks like an embarrassed Kirby holding a baby bottle. \$\endgroup\$ Feb 20, 2018 at 20:24
  • \$\begingroup\$ Can be just three characters now ≠⊂⊢ \$\endgroup\$
    – Tbw
    Feb 21 at 17:51
6
\$\begingroup\$

05AB1E, 8 bytes

Ùvyy¶ì.;

Try it online!


Always will output 1 preceding newline, which is constant and not indicative of a split, the 10-byte alternative that does not output a preceding newline is Ùvyy¶ì.;}¦, you can try that here. According to Adam a preceding or trailing newline is acceptable.


Input      = mississippi                               | Stack
-----------#-------------------------------------------+----------------------------------
Ù          # Push unique letters of first input.       | ['misp']
 v         # Iterate through each unique letter.       | []
  yy       # Push 2 copies of the letter (or yD)       | ['m','m']
    ¶      # Push a newline char.                      | ['m','m','\n']
     ì     # Prepended to the letter.                  | ['m','\nm']
      .;   # Replace first instance with '\n + letter' | ['\nmississippi']

After each iteration we get:

['\nmississippi'] > ['\nm\nississippi'] > ['\nm\ni\nssissippi'] > ['\nm\ni\nssissi\nppi']

Which is:

m
i
ssissi
ppi
\$\endgroup\$
5
  • \$\begingroup\$ Nice! Beat me by a fair margin ;) \$\endgroup\$
    – Emigna
    Feb 28, 2018 at 13:57
  • \$\begingroup\$ @Emigna this was sitting as a comment on your answer for 2 days then I just posted it b/c no response haha :P. \$\endgroup\$ Feb 28, 2018 at 14:06
  • \$\begingroup\$ Weird, haven't seen any notification on that. Different enough for its own answer though :) \$\endgroup\$
    – Emigna
    Feb 28, 2018 at 14:14
  • \$\begingroup\$ @Emigna well, I mean, I deleted it haha. \$\endgroup\$ Feb 28, 2018 at 15:56
  • 1
    \$\begingroup\$ Skipping the loop saves a byte ÙSD¶ì.;. Not sure why we didn't think of that before :P \$\endgroup\$
    – Emigna
    Mar 8, 2019 at 12:10
6
\$\begingroup\$

C,  75   65  63 bytes

Thanks to @Digital Trauma for saving 10 bytes and thanks to both @gastropner and @l4m2 for saving a byte each!

f(char*s){for(int l[128]={};*s;putchar(*s++))l[*s]++||puts(l);}

Prints a leading newline.

Try it online!

Without a leading newline (71 bytes):

f(char*s){int l[128]={};for(l[*s]=1;*s;putchar(*s++))l[*s]++||puts(l);}

Try it online!

\$\endgroup\$
2
  • 1
    \$\begingroup\$ 64 bytes \$\endgroup\$
    – gastropner
    Feb 21, 2018 at 15:30
  • \$\begingroup\$ {0} => {} ? \$\endgroup\$
    – l4m2
    Mar 9, 2018 at 23:02
5
\$\begingroup\$

Perl 6,  58 52  40 bytes

{$/={};.comb.classify({$+=!$/{$_}++}).sort».value».join}

Try it

*.comb.classify({$+=!(%){$_}++}).sort».value».join

Try it

*.classify({$+=!(%){$_}++}).sort».value

Try it
(input is a list of characters, and output is a list of lists of characters)

Expanded:

*                   # parameter for WhateverCode lambda

  .classify(        # classify that list
    {
        $           # anonymous scalar state variable (accumulator)

      +=            # increment it if:

        !           # Bool invert the following
          (
            %       # anonymous hash state variable
          ){ $_ }++ # look to see if the character was seen already
    }
  ).sort\           # sort the Pairs by key (makes the order correct)
  ».value           # get the value from each Pair

The output from classify is

{ # Hash
  1 => ['m'],
  2 => ['i'],
  3 => ['s','s','i','s','s','i'],
  4 => ['p','p','i'],
}

And .sort just turns it into:

[
  1 => ['m'],
  2 => ['i'],
  3 => ['s','s','i','s','s','i'],
  4 => ['p','p','i'],
]

».value removes the keys

[
  ['m'],
  ['i'],
  ['s','s','i','s','s','i'],
  ['p','p','i'],
]
\$\endgroup\$
2
  • \$\begingroup\$ Why would the keys ever be out of order? Is insertion order not tracked like a HashMap vs. a LinkedHashMap in Java where the order is based on memory vs. insert order? \$\endgroup\$ Feb 20, 2018 at 17:18
  • 1
    \$\begingroup\$ @MagicOctopusUrn No version of Perl has had ordered Hashes. In fact Perl 5 version 18 made Hashes more randomized which helps make a certain type of denial of service attack less possible, and has also caused buggy user code to expose it's buggy behaviour more often. Now someone could (and likely has) implement a class which does keep track, but that would take more than 5 characters to load and use. \$\endgroup\$ Feb 20, 2018 at 20:12
5
\$\begingroup\$

Haskell, 39 bytes

foldl(\s c->s++['\n'|all(/=c)s]++[c])""

Try it online!

Inserts a newline symbol before every character that appears for the first time, resulting in a newline-separated string, with a leading newline. Prepend lines. to produce a list.


Haskell, 55 bytes

(""%)
_%[]=[]
p%s|(a,b)<-span(`elem`s!!0:p)s=a:(a++p)%b

Try it online!

Repeatedly takes the prefix the first character plus the non-unique characters that follow it.

\$\endgroup\$
2
  • \$\begingroup\$ @WheatWizard Oops, yes, lines. \$\endgroup\$
    – xnor
    Feb 21, 2018 at 4:42
  • \$\begingroup\$ Might want to do tail.lines to remove the extra empty string now that I think about it. \$\endgroup\$
    – Wheat Wizard
    Feb 21, 2018 at 6:06
4
\$\begingroup\$

APL (Dyalog), 9 bytes

Thanks, Erik the Outgolfer for saving 1 byte!

⊢⊂⍨⍳∘≢∊⍳⍨

Try it online!

Explanation:

⍳⍨: For each character, get the index of its first occurrence. e.g mississippi -> 1 2 3 3 2 3 3 2 9 9 2

⍳∘≢: The range from 1 to the length of the input.

: Membership. e.g 1 2 3 4 5 6 7 8 9 10 11∊1 2 3 3 2 3 3 2 9 9 2 -> 1 1 1 0 0 0 0 0 1 0 0

⊢⊂⍨: Partition the input string with new partitions starting at 1s in the vector above

\$\endgroup\$
3
  • \$\begingroup\$ 9 bytes (monadic fg and monadic f∘g behave the same) \$\endgroup\$ Feb 19, 2018 at 18:37
  • \$\begingroup\$ Why instead of =? \$\endgroup\$
    – Adám
    Feb 20, 2018 at 9:32
  • \$\begingroup\$ At the time of writing, I hadn't considered that the indices would be in the correct positions. Although it is clear that they are \$\endgroup\$
    – H.PWiz
    Feb 20, 2018 at 17:01
4
\$\begingroup\$

Japt, 11 bytes

‰ r@=iRUbY

Test it online!

Explanation

This was inspired by Magic Octopus Urn's 05AB1E solution.

‰ r@=iRUbY    Implicit: U = input string
‰             Split U into chars, and keep only the first occurrence of each.
   r@          Reduce; for each char Y in this string...
        UbY      Find the first index of Y in U.
      iR         Insert a newline at this index in U.
     =           Set U to the result.
               As reduce returns the result of the last function call, this gives the
               value of U after the final replacement, which is implicitly printed.
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Japt is having an identity crisis here, it's calling itself Ruby for some reason. iRUbY! \$\endgroup\$ Feb 21, 2018 at 15:37
3
\$\begingroup\$

Python 2, 81 74 bytes

def f(s):d=sorted(map(s.find,set(s)));print map(lambda a,b:s[a:b],d,d[1:])

Try it online!

\$\endgroup\$
5
  • \$\begingroup\$ Save two with list(set(map(s.find,s))) \$\endgroup\$ Feb 19, 2018 at 19:41
  • \$\begingroup\$ @JonathanAllan it's a misleading side-effect, set do not keep order, counter-proof -> s='c'*6+'a'*100+'b' \$\endgroup\$
    – Rod
    Feb 19, 2018 at 19:59
  • \$\begingroup\$ I know we cannot rely on it in future implementations but I believe given ordered integers we maintain order in the set due to the hash of an integer being the integer (as you have shown the same is not true for other objects -- can you find a word that does not work with my alternative?). \$\endgroup\$ Feb 19, 2018 at 22:07
  • \$\begingroup\$ @JonathanAllan not true either \$\endgroup\$
    – Rod
    Feb 20, 2018 at 0:14
  • \$\begingroup\$ Ah, fair enough, my belief was false! \$\endgroup\$ Feb 20, 2018 at 0:22
3
\$\begingroup\$

JavaScript (ES6), 37 bytes

Saved 7 bytes: a leading newline was explicitly allowed (Thanks @Shaggy!)

Takes input as an array of characters. Outputs a newline-separated string.

s=>s.map(c=>s[c]=s[c]?c:`
`+c).join``

Test cases

let f =

s=>s.map(c=>s[c]=s[c]?c:`
`+c).join``

;[
  [..."mississippi"],
  [..."P P & C G"],
  [..."AAA"],
  [..."Adam"],
  [...""]    
]
.forEach(s => console.log('{' + f(s) + '}\n'))

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

brainfuck, 66 bytes

,[>+[<[>+<<-<+>>-]>[>]<<[[+]++++++++++.>>>]<]<[>+<-]>>>[>>]<<-.>,]

Formatted:

,
[
  >+
  [
    <[>+< <-<+>>-]
    >[>]
    <<[[+]++++++++++.>>>]
    <
  ]
  <[>+<-]
  >>>[>>]
  <<-.>,
]

Try it online

The leading newline in the output (which is only printed if the input is non-empty) can be removed at the cost of 5 bytes by replacing the body x of the main (outermost) loop with .>,[x].

\$\endgroup\$
2
\$\begingroup\$

Jelly, 6 bytes

ŒQœṗ⁸Ḋ

Try it online!

\$\endgroup\$
2
\$\begingroup\$

K4, 19 bytes

Solution:

$[#x;(*:'.=x)_;,]x:

Examples:

q)k)$[#x;(*:'.=x)_;,]x:"mississippi"
,"m"
,"i"
"ssissi"
"ppi"
q)k)$[#x;(*:'.=x)_;,]x:"P P & C G"
,"P"
" P "
"& "
"C "
,"G"
q)k)$[#x;(*:'.=x)_;,]x:"AAA"
"AAA"
q)k)$[#x;(*:'.=x)_;,]x:"Adam"
,"A"
,"d"
,"a"
,"m"
q)k)$[#x;(*:'.=x)_;,]x:""
,[""]

Explanation:

8 bytes is just to handle ""...

$[#x;(*:'.=x)_;,]x: / the solution
                 x: / save input as variable x
$[  ;         ; ]   / $[condition;true;false]
  #x                / length of x ("" has length 0, i.e. false)
             _      / cut right at left indices
     (      )       / do together
          =x        / group x into key/value (char!indices)
         .          / return value (get indices)
      *:'           / first (*:) each
               ,    / enlist, "" => [""]
\$\endgroup\$
2
\$\begingroup\$

Perl, 30 bytes

Includes +1 for p

Give input without trailing newline on STDIN. Output is also without trailing newline:

echo -n adam | perl -pE 's%.%$v{$&}+++!pos?$&:$/.$&%eg'; echo

If you don't care about leading and trailing newlines this 25 (+3 for -p because the code contains ') also works:

#!/usr/bin/perl -p
s%%$/x!$v{$'&~v0}++%eg
\$\endgroup\$
5
  • \$\begingroup\$ Great solution as always! Based on the test cases provided, you don't need to name your hash, you can do ${$&}++. It's not as robust, but might suffice for this challenge? Also, there's been a consensus on meta that perl -p doesn't need an additional byte, you just need to have the header as Perl with `-p` instead of just Perl. I'm trying to remember to do that myself... \$\endgroup\$ Feb 20, 2018 at 10:08
  • \$\begingroup\$ @DomHastings The annecdote about at most 95 possible strings quite strongly implies that 1 is valid, in which case the v is needed. Regarding the counting, I mostly follow codegolf.meta.stackexchange.com/a/7539/51507 which to me is the most consistent meta post about counting perl. \$\endgroup\$
    – Ton Hospel
    Feb 20, 2018 at 13:04
  • \$\begingroup\$ Always nice to learn from the master. Specifically, in this case, &~v0 for grabbing the first character. Thank you for joining this site and sharing your long expertise. \$\endgroup\$
    – msh210
    Mar 6, 2018 at 21:54
  • \$\begingroup\$ You can use Strawberry Perl, which uses " instead of ' with -e, and then you can count the -ep as +1 rather than +3. (Tested.) \$\endgroup\$
    – msh210
    Mar 6, 2018 at 22:06
  • \$\begingroup\$ Redoing your 30 byte solution which does not put in a leading newline, I think you can save by using a negative lookbehind to skip the first newline. That way, the use of pos can be eliminated, also removing the need for the conditional operator. Try it online! \$\endgroup\$
    – Xcali
    Feb 21 at 17:48
2
\$\begingroup\$

JavaScript, 61 54 52 bytes

Takes input as an array of characters.

s=>s.map(x=>a[x]?a[y]+=x:a[x]=a[++y]=x,a=[],y=-1)&&a

Try it

o.innerText=JSON.stringify((f=
s=>s.map(x=>a[x]?a[y]+=x:a[x]=a[++y]=x,a=[],y=-1)&&a
)([...i.value=""]));oninput=_=>o.innerText=JSON.stringify(f([...i.value]))
<input id=i><pre id=o></pre>

\$\endgroup\$
2
\$\begingroup\$

R, 94 87 bytes

function(s,n=nchar(s),g=substring)g(s,d<-which(!duplicated(g(s,1:n,1:n))),c(d[-1]-1,n))

Try it online!

Returns a (possibly empty) list of substrings.

Thanks to Michael M for saving 7 bytes!

\$\endgroup\$
7
  • 3
    \$\begingroup\$ function(s,n=nchar(s),g=substring)g(s,d<-which(!duplicated(g(s,1:n,1:n))),c(d[-1]-1,n)) would be shorter - and of course a bit uglier... \$\endgroup\$
    – Michael M
    Feb 19, 2018 at 20:25
  • \$\begingroup\$ Why substring instead of substr? \$\endgroup\$
    – plannapus
    Feb 20, 2018 at 9:48
  • \$\begingroup\$ @MichaelM Very nice! I still have to add the if(n) in there because substring throws an error for empty string input. \$\endgroup\$
    – Giuseppe
    Feb 20, 2018 at 12:20
  • 1
    \$\begingroup\$ @plannapus substr returns a vector of length equal to its first input while substring returns one of length equal to the longest of its inputs. \$\endgroup\$
    – Giuseppe
    Feb 20, 2018 at 12:22
  • \$\begingroup\$ @Giuseppe: Dropping the "if(n)" in R 3.4.3 maps the empty input string "" to the empty output string "", which should be fine(?) \$\endgroup\$
    – Michael M
    Feb 20, 2018 at 14:51
2
\$\begingroup\$

Stax, 8 bytes

ç↓‼►▐NVh

Run and debug online

The ascii representation of the same program is this.

c{[Ii=}(m

For each character, it splits when the index of the current character is the current position.

c            copy the input
 {    }(     split the string when the result of the enclosed block is truthy
  [          duplicate the input string under the top of the stack
   I         get the character index of the current character
    i=       is it equal to the iteration index?
        m    print each substring
\$\endgroup\$
2
\$\begingroup\$

><>, 22 17 14 bytes

-1 byte thanks to Emigna

i:::a$1g?!o1po

Try it online!

Prints a leading and trailing newline.

It keeps track of which letters have already appeared by putting a copy of the character at that corresponding spot on the second row, and printing a newline if the value fetched from that position was not 1. Ends in an error when it tries to print -1

\$\endgroup\$
1
  • \$\begingroup\$ Great use of g/p! 16 bytes \$\endgroup\$
    – Emigna
    Mar 8, 2019 at 12:22
2
\$\begingroup\$

BQN, 11 6 bytes

⌈`∘⊐⊸⊔

Try it at BQN online!

Explanation

⌈`∘⊐⊸⊔
   ⊐    Classify: replace each letter with a number based on the order of
        their first occurrences
⌈`∘     Scan with maximum: replace each number with the largest number so far
    ⊸⊔  Group the original string into those buckets

A couple of worked examples:

"dodos"            "Mississippi"
⟨ 0 1 0 1 2 ⟩       ⟨ 0 1 2 2 1 2 2 1 3 3 1 ⟩
⟨ 0 1 1 1 2 ⟩       ⟨ 0 1 2 2 2 2 2 2 3 3 3 ⟩
⟨ "d" "odo" "s" ⟩   ⟨ "M" "i" "ssissi" "ppi" ⟩
\$\endgroup\$
1
\$\begingroup\$

Haskell, 62 bytes

r#c|any(elem c)r=init r++[last r++[c]]|1<2=r++[[c]]
foldl(#)[]

Try it online!

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

JavaScript (ES6), 68 bytes

s=>s.map(c=>o[c]?t+=c:(t&&m.push(t),t=o[c]=c),t='',o=m=[])&&[...m,t]

Takes input as a list of characters.

Test cases:

let f=
s=>s.map(c=>o[c]?t+=c:(t&&m.push(t),t=o[c]=c),t='',o=m=[])&&[...m,t]

console.log(f([...'mississippi']));
console.log(f([...'P P & C G']));
console.log(f([...'AAA']));
console.log(f([...'Adam']));
console.log(f([...'']));

\$\endgroup\$
2
  • \$\begingroup\$ I had a similar solution and asked if [""] was acceptable for the last test case. But it's not. :-( \$\endgroup\$
    – Arnauld
    Feb 19, 2018 at 23:27
  • \$\begingroup\$ Oh, well, you got a much better solution anyway : ) \$\endgroup\$ Feb 20, 2018 at 0:36
1
\$\begingroup\$

Python 2, 47 bytes

lambda s:reduce(lambda r,c:r+'\n'[c in r:]+c,s)

Try it online!

Outputs a newline-separated string. Barely beats the program version:

Python 2, 48 bytes

r=''
for c in input():r+='\n'[c in r:]+c
print r

Try it online!

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

PHP, 317 bytes

function SplitOnFirstUnique($s){
    $len = strlen($s); 
    $output = [];
    $newstring = '';
    for ($i=0; $i < $len ; $i++) { 
        $newstring = $newstring.$s[$i];
        if(!in_array($s[$i] , $output  )){
            $output[] = $newstring;
            $newstring = '';
        }
    }
    return $output;
}

Try it online!

\$\endgroup\$
1
  • 2
    \$\begingroup\$ Hello, and welcome to PPCG! I've edited your post to our standard format, and added a link to Try It Online so other people can test your code. The aim of Code Golf is to write the shortest code possible, and I can see a couple of ways to make this shorter, like using shorter variable names and leaving out some of the whitespace. You can check out the general tips and PHP tips pages for some more ideas. \$\endgroup\$
    – Not a tree
    Feb 20, 2018 at 6:34
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\$

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

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.