g | x | w | all
Bytes Lang Time Link
nan250227T193303Zxrs
055Zsh250218T071755Zroblogic
003TinyAPL250217T163929Znoodle p
010Husk250217T134801ZGlory2Uk
082R240705T191226ZDominic
031JavaScript Node.js240705T205806Zl4m2
008Japt240705T162543ZShaggy
042Arturo240705T161831Zchunes
086R240705T100139ZGlory2Uk
109Scala 3240227T105019Zt9dupuy
005Vyxal240226T221737Zemanresu
006BQN240221T235737ZDLosc
003APL Dyalog APL240221T173040ZAdá
022Perl 5 + pl240221T085228ZDom Hast
006Uiua SBCS240221T071045Zchunes
040Ruby221020T161846ZJordan
159Java 8190308T221042ZBenjamin
014><>180220T050800ZJo King
096Clojure190308T120235ZNikoNyrh
020Gema190308T124259Zmanatwor
061PowerShell190308T044407Zmazzy
151Java 8180220T090359ZKevin Cr
066brainfuck180718T190524ZMitch Sc
063C180219T182425ZSteadybo
058Ruby180219T224740Zbenj2240
087JavaScript180305T214601ZSebasti&
063AWK180221T190403ZRobert B
039Haskell180219T213745Zxnor
011Japt180220T231432ZETHprodu
037JavaScript ES6180219T235055ZArnauld
073PowerShell180220T231132ZDon Crui
008Stax180220T192625Zrecursiv
00805AB1E180220T183439ZMagic Oc
077SNOBOL4 CSNOBOL4180219T191106ZGiuseppe
176C++180220T150111ZHatsuPoi
087R180219T191809ZGiuseppe
037GNU sed180220T135451ZToby Spe
074Lua180220T121427ZJonathan
052JavaScript180219T235014ZShaggy
019Retina 0.8.2180219T200020ZNeil
079Red180220T082317ZGalen Iv
030Perl180220T065511ZTon Hosp
317PHP180220T052122ZSaurabh
009APL Dyalog180219T183643ZH.PWiz
047Python 2180220T003259Zxnor
074Python 2180219T190016ZRod
037Perl 5 + p180219T215918Zwastl
068JavaScript ES6180219T215006ZRick Hit
084Mathematica180219T213722ZLegionMa
019K4180219T210646Zmkst
200Javascript180219T202053Zaimorris
062Haskell180219T201645Znimi
004Jelly180219T182313ZZgarb
008APL Dyalog Unicode180219T194503Zngn
007J180219T192050Zcole
nan180219T190729ZBrad Gil
01105AB1E180219T180150ZEmigna
009Retina180219T180144ZMartin E
006Jelly180219T180036ZErik the

AWK, 39 bytes

{for(;i++<NF;)printf++b[$i]<2?" "$i:$i}

Attempt This Online!

{for(;i++<NF;) # traverse chars
printf         #
++b[$i]<2      # have we seen this char before
?" "$i:$i}     # insert space if necessary

Zsh, 55 bytes

for i (${(s::)1}){((${#i:|P}))&&echo;printf $i;P+=($i)}

Try it online!

Based on my uniqchars solution. Builds array P. If $i is not in P already, print a newline.

TinyAPL, 3 bytes

≠⊸⊂

Nub sieve () makes this task pretty trivial. Here's another version, without it:

TinyAPL, 16 bytes

{⍵⊆⍨+/⍉⌈/↟=ᓗ⟜∪⍵}

Husk, 10 bytes

Ẋ-:mo←x¹u¹

Try it online!

Commented:

        u  -- get unique characters
           -- for "mississippi" these would be m,i,s,p
   mo      -- map two functions:
       x¹  -- | split the input at every occurence of the corresponding unique character
     ←    -- | take the first element of each sublist
           -- | the result: ["","m","mi","mississi"]
  :      ¹ -- add the starting string to the end of the list
Ẋ-         -- perform pairwise subtraction

R, 83 82 bytes

function(s)if(s>"")substring(s,i<-which(!duplicated(utf8ToInt(s))),c(i[-1],1e6)-1)

Try it online!

Different approach to int 21h Glory to Ukraine's answer.

Note, though, that int 21h Glory to Ukraine could still beat this by reverting to the (allowed) output format of a single newline-separated string.

(Edit: after scrolling down after posting, I noticed that this approach is similar an earlier answer by Giuseppe, but saves some bytes by using utf8ToInt instead of substring to split-up the input vector).

JavaScript (Node.js), 31 bytes

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

Try it online!

Pure regex

Japt, 8 bytes

ò@bY ¶°T

Try it

Arturo, 42 bytes

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

Try it!

R, 86 bytes

function(s)strsplit(intToUtf8(Reduce(function(a,b)c(a,9*!b%in%a,b),utf8ToInt(s))),"	")

Try it online!

Based on the great +1 xnor's answer with some R-specific features.

Takes a string as an input and outputs a vector of strings.

EDIT: added strsplit(...) to output as a vector.

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!

Vyxal, 5 bytes

ÞUÞṗḢ

Try it Online!

  Þṗ  # Partition before
ÞU    # Uniquity mask
    Ḣ # Remove leading empty list

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

APL (Dyalog APL), 3 bytes

≠⊂⊢

Attempt This Online!

 the Boolean mask indicating first occurrence of each character…

 splits…

 the argument

Perl 5 + -pl, 22 bytes

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

Try it online!

Uiua SBCS, 6 bytes

⊜□\+◰.

Try it!

⊜□\+◰.
     .  # duplicate
    ◰   # mark firsts
  \+    # cumulative sum
⊜□      # split

Ruby, 40 bytes

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

Attempt This Online!

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!

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

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

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!

PowerShell, 61 bytes

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

Try it online!

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)

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

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!

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

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!

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.

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.

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.

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

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

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

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

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.

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

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!

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.

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.

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>

Retina 0.8.2, 22 20 19 bytes

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

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

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

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

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!

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

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!

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!

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!

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([...'']));

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.

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, "" => [""]

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

Haskell, 62 bytes

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

Try it online!

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.

APL (Dyalog Unicode), 8 bytesSBCS

(≢¨∪\)⊆⊢

Try it online!

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

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'],
]

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 "" -> [])

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 ¶$&.

Jelly, 6 bytes

ŒQœṗ⁸Ḋ

Try it online!