12
\$\begingroup\$

Given a string, return a table where the first column has the unique letters of the string in order of occurrence and subsequent columns list the indices of that letter in the string, using zero or one-based indexing. Horizontal whitespace does not matter, as long as the left-most column is vertically aligned. Indices must be in ascending order from left to right.

Examples

Using zero-based indexing and given "abracadabra", return

a 0 3 5 7 10
b 1 8       
r 2 9       
c 4         
d 6   

Using one-based indexing and given "3141592653589793238462643383279503", return:

3  1 10 16 18 25 26 28 34
1  2  4                  
4  3 20 24               
5  5  9 11 32            
9  6 13 15 31            
2  7 17 22 29            
6  8 21 23               
8 12 19 27               
7 14 30                  
0 33                     
\$\endgroup\$
8
  • \$\begingroup\$ Can I have leading spaces in the output? \$\endgroup\$ Commented Jun 20, 2017 at 13:20
  • \$\begingroup\$ Must the output format be strict? \$\endgroup\$
    – Leaky Nun
    Commented Jun 20, 2017 at 13:21
  • \$\begingroup\$ @EriktheOutgolfer Yes. Added. \$\endgroup\$
    – Adám
    Commented Jun 20, 2017 at 13:22
  • \$\begingroup\$ @LeakyNun No. Added. \$\endgroup\$
    – Adám
    Commented Jun 20, 2017 at 13:22
  • 2
    \$\begingroup\$ Does this need to work for characters that aren't printable ascii? Are there any characters we can assume won't be in the string (particularly whitespace)? \$\endgroup\$ Commented Jun 20, 2017 at 16:18

19 Answers 19

6
\$\begingroup\$

APL (Dyalog), 4 bytes

,⌸

Try it online!

( is 3 bytes)

Uses 1-based indexing.

is the key operator. Here it behaves as a monadic operator. It applies the function ,, concatenate the left argument with the right argument, to each unique element in its right argument and the indices of that unique element in the original argument.

\$\endgroup\$
4
  • \$\begingroup\$ Hm, this needs an explanation :-) \$\endgroup\$
    – Adám
    Commented Jun 20, 2017 at 13:53
  • 4
    \$\begingroup\$ @Adám I suspect this challenge had been tailored specifically for APL 😉 \$\endgroup\$
    – Uriel
    Commented Jun 20, 2017 at 14:30
  • \$\begingroup\$ @Uriel The other way around. I was looking at what APL can do neatly, and thought that this would make a good challenge. \$\endgroup\$
    – Adám
    Commented Jun 20, 2017 at 14:32
  • \$\begingroup\$ I see 4 bytes there. \$\endgroup\$
    – Adám
    Commented Jun 20, 2017 at 14:32
2
\$\begingroup\$

Haskell, 86 bytes

import Data.List
f s=unlines[x:concat[' ':show i|i<-[0..length s-1],s!!i==x]|x<-nub s]

Defines a function, f, which returns a String containing this output.

Try it online!

How?

import Data.List                                                            -- Imports Data.List. This contains the nub method which is necessary
f s =                                                                       -- Define a function, f, which takes one argument, s
            [                                               |x<-nub s]      -- Loop through nub s with the variable x. Nub removes duplicates from a list, in this case the input.
                     [          |i<-[0..length s-1]        ]                -- Go thourgh the list [0,1,2...] until the length of the input - 1. Basically a indexed for-loop
                                                   ,s!!i==x                 -- Filter out everything where the char at this index isn't x
                      ' ':show i                                            -- i as a string with a space before it
               concat                                                       -- Flatten the whole list
             x:                                                             -- Append x before it
     unlines                                                                -- Insert newlines between every element in the list and flatten it, effectively putting every element on it's own line
\$\endgroup\$
2
  • 2
    \$\begingroup\$ I don't think I've ever seen that comment format used for Haskell. \$\endgroup\$
    – Adám
    Commented Jun 20, 2017 at 13:53
  • \$\begingroup\$ Your inner list comprehension can be shortened to [' ':show i|(i,c)<-zip[0..]s,c==x]. \$\endgroup\$
    – Laikoni
    Commented Jun 20, 2017 at 15:47
2
\$\begingroup\$

kdb+/q, 5 bytes

group

Builtins are fab

q)group"abracadabra"
a| 0 3 5 7 10
b| 1 8
r| 2 9
c| ,4
d| ,6

I usually golf in k, but the 2-byte k version (=:) doesn't format the output nicely

k)=:"abracadabra"
"abrcd"!(0 3 5 7 10;1 8;2 9;,4;,6)

The results are exactly the same, but the formatting is lost. To format, and to remove the return object, we actually pick up more bytes than the q version

k)f:{[email protected] x;} //11 bytes!
k)f"abracadabra"
a| 0 3 5 7 10
b| 1 8
r| 2 9
c| ,4
d| ,6
\$\endgroup\$
1
  • \$\begingroup\$ Hm, it returns a dictionary. Interesting. \$\endgroup\$
    – Adám
    Commented Jun 20, 2017 at 15:37
1
\$\begingroup\$

Python, 96 bytes

def f(s,r=[]):
 for c in s:
  if c not in r:print(c,*(i for i,l in enumerate(s) if l==c));r+=[c]

try it online!

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

MATL, 11 bytes

u"@0hG@=fVh

Output indices are 1-based.

Try it online!

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

Pyth, 13 bytes

jmj;+dxCdCMQ{

Try it online!

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

Jelly, 7 bytes

Q;"ĠṢ$G

Try it online!

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

05AB1E, 14 bytes

ÙvSyQƶ0Ky¸ìðý,

Try it online!

Explanation

Ùv              # for each unique char y in input
  S             # split input into a list of chars
   yQ           # compare each to y for equality
     ƶ          # multiply each by its 1-based index
      0K        # remove zeroes
        y¸ì     # prepend y to the list of indices
           ðý,  # join by spaces and print
\$\endgroup\$
0
\$\begingroup\$

Mathematica, 85 bytes

using one-based indexing

(t=#;j=First/@t~StringPosition~#&/@(s=First/@Tally@Characters@t);Row[Column/@{s,j}])&
\$\endgroup\$
0
\$\begingroup\$

JavaScript (ES Draft), 77 bytes

s=>s.replace(/./g,(c,i)=>a[c]=(a[c]||c)+` `+i,a={})&&Object.values(a).join`
`

88 bytes in older browsers:

f=
s=>s.replace(/./g,(c,i)=>a[c]=(a[c]||c)+` `+i,a={})&&Object.keys(a).map(c=>a[c]).join`
`
<input oninput=o.textContent=f(this.value)><pre id=o>

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

PHP, 82 bytes

for(;~$c=$argn[$i];)$r[$c].=str_pad(++$i,5," ",0);foreach($r as$k=>$v)echo"$k$v
";

Try it online!

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

QBIC, 95 bytes

dim X(126)[_l;||i=asc(_sA,a,1|)┘X(i)=X(i)+@ `+!a$][_lA||_SA,b,1|i=asc(C)~X(i)<>D|?C,X(i)┘X(i)=@

Explanation

This copies significant parts of my answer on this challenge:

dim x(126)      Create an array of 126 elements (one for each ASCII element)
[_l;||          Read cmd line input, loop over its length
i=asc(_sA,a,1|) Read the next char's ascii value
┘               (Syntactic linebreak)
X(i)=           Set the value for this ascii-codepoint to
 X(i)             everything we've put in before
 +@ `             and a literal space
 +!a$             and the current (1-based) index cast as string
 ]              close the FOR loop
 [_lA||         Loop over the original string again (to preserve order of appearance)
 _SA,b,1|       Read 1 char, assign to C$ (note the capital S in the function call,
                this auto-creates C$ abd assigns it the value of the substring-call)
 i=asc(C)       Get the index in our storage array from C$'s ascii value
 ~X(i)<>D       IF the storage array holds data for i (<> D$, which we'll set to "" in a second), 
 |?C,X(i)       THEN PRINT the character, followed by the indices saved for this char
 ┘              (Syntactic linebreak)
 X(i)=@         Clear out the data stored for C$
                @ declares a string lit, ` would close it and that gets auto-added at EOF, 
                creating the literal @`, which gets assigned to D$

Sample run:

Command line: abracadabra
a              1 4 6 8 11
b              2 9
r              3 10
c              5
d              7
\$\endgroup\$
0
\$\begingroup\$

C (clang), 176 bytes

G(S,V,c,g,i,H,L)char*S,*V;{for(V=malloc(8),H=strlen(S),c=g=-1;++g<H;){if(strchr(V,L=S[g]))continue;printf("%c ",V[c++]=L);for(i=-1;++i<H;printf(S[i]==L?"%d ":"",i));puts("");}}

Of course this is the longest answer here...

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ Where is the Java solution? \$\endgroup\$
    – Adám
    Commented Jun 21, 2017 at 6:35
  • \$\begingroup\$ 164 bytes \$\endgroup\$
    – ceilingcat
    Commented Jul 31, 2019 at 5:19
0
\$\begingroup\$

Python 3, 111 106 bytes

def q(f):
 d={a:[]for a in f}
 for a,b in enumerate(f):d[b]+=[a]
 [print(p,*d.pop(p))for p in f if p in d]

repl.it

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

C#, 138 bytes

using System.Linq;s=>Console.Write(string.Join("\n",s.Distinct().Select(c=>c+string.Join("",s.Select((d,i)=>d==c?i:-1).Where(i=>i>-1)))));
\$\endgroup\$
0
\$\begingroup\$

F#, 120 bytes

let f s=s|>Seq.indexed|>Seq.groupBy(fun(a,b)->b)|>Seq.iter(fun(a,b)->
 printf"\n%c"a 
 Seq.iter(fun(c,_)->printf"%i"c)b)

A more readable version:

let f s =
    s
    |> Seq.indexed
    |> Seq.groupBy (fun (idx, char) -> char)
    |> Seq.iter (fun (char, charIdxSeq) ->
         printf "\n%c" char 
         Seq.iter (fun (idx, _) -> printf "%i" idx) charIdxSeq)

Seq.indexed creates a new sequence containing tuples which are composed of the original element and it's 0 based index in the original sequence.

The rest is fairly self explanatory which is never a good thing for golf!

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

R, 80 77 bytes

function(s)for(i in (z=unique(s<-strsplit(s,'')[[1]])))cat(i,which(s==i),"
")

Try it online!

an anonymous function; prints the result 1-indexed with a trailing newline.

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

J, 11 bytes

~.,.":@I.@=

Try it online!

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

Husk, 10 bytes

§mȯ§:;ms¥u

Try it online!

Note: Husk (or at least the command ¥) is newer than this challenge.

Explanation

§mȯ§:;ms¥u  Implicit input, say S = "ababbc".
         u  Remove duplicates: "abc"
§m          Map over this string:
             Argument is a character, say 'b'.
        ¥    1-based indices in S: [2,4,5]
      ms     Convert each to string: ["2","4","5"]
     ;       Wrap argument in a string: "b"
  ȯ§:        Prepend to list of index strings: ["b","2","4","5"]
            Result is a list of lists of strings
             [["a","1","3"],["b","2","4","5"],["c","6"]]
            Implicitly print, separating strings by spaces and lists by newlines.
\$\endgroup\$

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.