Make a lookup index

12

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                     

Adám

Posted 2017-06-20T13:20:17.507

Reputation: 37 779

Can I have leading spaces in the output? – Erik the Outgolfer – 2017-06-20T13:20:50.337

Must the output format be strict? – Leaky Nun – 2017-06-20T13:21:38.930

@EriktheOutgolfer Yes. Added. – Adám – 2017-06-20T13:22:17.067

@LeakyNun No. Added. – Adám – 2017-06-20T13:22:22.740

Can the rows be unordered? – Erik the Outgolfer – 2017-06-20T13:25:06.600

@Adám I meant if instead of abrcd I output abcdr for example, with the indices still corresponding to the correct letters. – Erik the Outgolfer – 2017-06-20T13:26:54.147

@EriktheOutgolfer OP: in order of occurrence – Adám – 2017-06-20T13:27:17.667

2Does 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)? – FryAmTheEggman – 2017-06-20T16:18:53.233

Answers

6

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.

user41805

Posted 2017-06-20T13:20:17.507

Reputation: 16 320

Hm, this needs an explanation :-) – Adám – 2017-06-20T13:53:43.713

4@Adám I suspect this challenge had been tailored specifically for APL – Uriel – 2017-06-20T14:30:19.520

@Uriel The other way around. I was looking at what APL can do neatly, and thought that this would make a good challenge. – Adám – 2017-06-20T14:32:02.693

I see 4 bytes there. – Adám – 2017-06-20T14:32:36.907

2

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

Loovjo

Posted 2017-06-20T13:20:17.507

Reputation: 7 357

2I don't think I've ever seen that comment format used for Haskell. – Adám – 2017-06-20T13:53:17.197

Your inner list comprehension can be shortened to [' ':show i|(i,c)<-zip[0..]s,c==x]. – Laikoni – 2017-06-20T15:47:28.607

2

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:{1@.Q.s x;} //11 bytes!
k)f"abracadabra"
a| 0 3 5 7 10
b| 1 8
r| 2 9
c| ,4
d| ,6

Simon Major

Posted 2017-06-20T13:20:17.507

Reputation: 401

Hm, it returns a dictionary. Interesting. – Adám – 2017-06-20T15:37:18.297

1

MATL, 11 bytes

u"@0hG@=fVh

Output indices are 1-based.

Try it online!

Luis Mendo

Posted 2017-06-20T13:20:17.507

Reputation: 87 464

1

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!

Uriel

Posted 2017-06-20T13:20:17.507

Reputation: 11 708

0

Jelly, 7 bytes

Q;"ĠṢ$G

Try it online!

Erik the Outgolfer

Posted 2017-06-20T13:20:17.507

Reputation: 38 134

0

Pyth, 13 bytes

jmj;+dxCdCMQ{

Try it online!

Leaky Nun

Posted 2017-06-20T13:20:17.507

Reputation: 45 011

0

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

Emigna

Posted 2017-06-20T13:20:17.507

Reputation: 50 798

0

Mathematica, 85 bytes

using one-based indexing

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

J42161217

Posted 2017-06-20T13:20:17.507

Reputation: 15 931

0

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.

Giuseppe

Posted 2017-06-20T13:20:17.507

Reputation: 21 077

0

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>

Neil

Posted 2017-06-20T13:20:17.507

Reputation: 95 035

0

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!

Jörg Hülsermann

Posted 2017-06-20T13:20:17.507

Reputation: 13 026

0

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

steenbergh

Posted 2017-06-20T13:20:17.507

Reputation: 7 772

0

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

Wondercricket

Posted 2017-06-20T13:20:17.507

Reputation: 251

0

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!

R. Kap

Posted 2017-06-20T13:20:17.507

Reputation: 4 730

Where is the Java solution? – Adám – 2017-06-21T06:35:51.360

164 bytes – ceilingcat – 2019-07-31T05:19:38.070

0

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

user20151

Posted 2017-06-20T13:20:17.507

Reputation:

0

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!

user20151

Posted 2017-06-20T13:20:17.507

Reputation:

0

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.

Zgarb

Posted 2017-06-20T13:20:17.507

Reputation: 39 083

0

J, 11 bytes

~.,.":@I.@=

Try it online!

FrownyFrog

Posted 2017-06-20T13:20:17.507

Reputation: 3 112