50
\$\begingroup\$

The input is a word of lowercase letters not separated by whitespace. A newline at the end is optional.

The same word must be output in a modified version: For each character, double it the second time it appears in the original word, triple it the third time etc.

Example input:

bonobo

Example output:

bonoobbooo

Standard I/O rules apply. The shortest code in bytes wins.

Tests provided by @Neil :

tutu -> tuttuu
queue -> queuuee
bookkeeper -> boookkkeeepeeer
repetitive -> repeetittiiveee
uncopyrightables -> uncopyrightables
abracadabra -> abraacaaadaaaabbrraaaaa
mississippi -> misssiisssssssiiipppiiii
\$\endgroup\$

38 Answers 38

36
\$\begingroup\$

Jelly, 4 bytes

;\f"

Try it online!

How it works

;\f"  Main link. Argument: S (string)

;\    Cumulatively reduce by concatenation.
      This yields the array of all prefixes of S.
  f"  Vectorized filter.
      Keep only occurrences of the nth letter in the nth prefix.
\$\endgroup\$
  • 21
    \$\begingroup\$ Well then... rip Pyth. \$\endgroup\$ – Adnan Apr 4 '16 at 14:16
  • 2
    \$\begingroup\$ This site is becoming a competition for the best general-purpose golfing language... not that that's a bad thing. \$\endgroup\$ – Shelvacu Apr 4 '16 at 23:34
  • 8
    \$\begingroup\$ @shelvacu The latter is debatable, 2 friends I've shown PPCG to have said something along the lines of "all the top answers are just using golf languages" as a first impression. \$\endgroup\$ – Insane Apr 5 '16 at 6:37
  • \$\begingroup\$ @Insane there is/ are. Code golf is a pretty common thing. So languages are put together for that purpose, exclusively. \$\endgroup\$ – Evan Carslake Apr 6 '16 at 23:53
  • \$\begingroup\$ How does this.... work? \$\endgroup\$ – Erik the Outgolfer Oct 4 '16 at 15:22
21
\$\begingroup\$

Pyth, 6 bytes

Thanks to @Doorknob for taking off 1 byte.

Thanks to @Maltysen for taking off 5 bytes.

s@VQ._

Try it online!

How it works


For example, take the string "bonobo".

._ makes a list: ['b', 'bo', 'bon', 'bono', 'bonob', 'bonobo']

VQ._ means "the preceding function vectorized (applied in parallel) over Q and ._", which means Q (the input evaluated) will be treated as a list: ['b', 'o', 'n', 'o', 'b', 'o'], and then they will be paired by the @ like this:

     Q      ._         @ (intersect)
0:  'b'     'b'       'b'
1:  'o'     'bo'      'o'
2:  'n'     'bon'     'n'
3:  'o'     'bono'    'oo'
4:  'b'     'bonob'   'bb'
5:  'o'     'bonobo'  'ooo'

Therefore, @VQ._ will produce ['b', 'o', 'n', 'oo', 'bb', 'ooo'].

The s then joins them all together, creating a string 'bonoobbooo', which is then implicitly printed out to become bonoobbooo.

\$\endgroup\$
  • 2
    \$\begingroup\$ Kenny, your explanation is wrong. VQ only means for N in Q when it is not inside a function. In this case, what's actually going on is that @V means the @ function vectorized (applied in parallel) over its next two arguments, Q and ._. This is missing from the docs, so I'll fix it. \$\endgroup\$ – isaacg Apr 5 '16 at 6:11
14
\$\begingroup\$

Retina, 34 19 bytes

Saved 15 bytes by taking some inspiration from isaacg's solution.

Byte count assumes ISO 8859-1 encoding.


$`¶
(\D)(?!.*\1¶)

The leading and trailing empty lines are significant.

Try it online!

Explanation


$`¶

This is a replace stage which matches the empty regex (i.e. every zero-width position in the string) and substitutes $`¶ for it, where $` is the prefix of the match and inserts a linefeed. This basically computes all the prefixes and puts them on a separate line together with the last character of that prefix:

bb
obo
oboo
kbook
kbookk
ebookke
ebookkee
pbookkeep
ebookkeepe
rbookkeeper

There will be some leading and trailing linefeeds, but we can ignore them.

From each of these prefixes we want to keep the characters that are equal to the last character. For that we use another replace stage:

(\D)(?!.*\1¶)

This matches everything we don't want to keep and replaces it with a nothing. We match any character (using \D since we know there won't be digits in the input) and then make sure that there isn't another copy of that character at the end of the line.

\$\endgroup\$
11
\$\begingroup\$

Python, 56 bytes

I seem to be stuck with two answers of the same length:

f=lambda x,*y:x and-~y.count(x[0])*x[0]+f(x[1:],x[0],*y)
f=lambda x,y=0:x[y:]and-~x[:y].count(x[y])*x[y]+f(x,y+1)

Edit: See @pacholik's answer for a shorter, alternative Python approach.

\$\endgroup\$
  • \$\begingroup\$ I'm not used to beating you with my ><> answers, I'm waiting for a Gol><> answer to fix that ;) \$\endgroup\$ – Aaron Apr 4 '16 at 12:48
  • \$\begingroup\$ @Aaron Too bad, I was actually going to beat you back with ><> :P \$\endgroup\$ – Sp3000 Apr 4 '16 at 13:01
  • \$\begingroup\$ Line noise in Python? What heresy! \$\endgroup\$ – cat Apr 6 '16 at 13:27
  • \$\begingroup\$ What does -~ do? I know it's bitwise NOT followed by negation, but what are you trying to do that it saves a few bytes on? \$\endgroup\$ – Fund Monica's Lawsuit Apr 7 '16 at 20:30
  • 2
    \$\begingroup\$ @QPaysTaxes It's increment +1 with high enough precedence so that parens aren't necessary \$\endgroup\$ – Sp3000 Apr 7 '16 at 20:38
10
\$\begingroup\$

Haskell, 39 bytes

f""=""
f x=f(init x)++filter(==last x)x

Usage example: f "bonobo" -> "bonoobbooo".

Different enough from @Damien's answer. Builds the string from the right by extracting all occurrences of the last character from the string and prepending a recursive call with all but the last character.

\$\endgroup\$
9
\$\begingroup\$

><>, 27 bytes

>i:0g1+:\
:{-1v!?:<}o
/p${/

Requires the official interpreter which exits with an error when trying to print code point -1. Try it online!

The code reads input one char at a time and uses the first row of the codebox as a large array which stores the number of times each char has been seen so far (><> initialises non-program cells to 0). The second row is a loop for outputting a char multiple times.

Alternatively, here's a version which exits cleanly (37 bytes, not properly golfed):

>i:0(?;:0g1+:\
}o:{-1v!?:   <
v  p${<
\$\endgroup\$
  • \$\begingroup\$ Damn that's good ! I should stop relying so heavily on the online interpreter, I would never have thought about simply using such a huge codebox, and I didn't even knew the official interpreter exited on -1 print \$\endgroup\$ – Aaron Apr 4 '16 at 13:11
  • 2
    \$\begingroup\$ @Aaron Yeah, it's a corollary of Python erroring when trying to do chr(-1). The animated interpreter's great for visualisations, but unfortunately some of the discrepancies with the official interpreter are a bit annoying :/ \$\endgroup\$ – Sp3000 Apr 4 '16 at 13:15
9
\$\begingroup\$

JavaScript (ES6), 48 45 bytes

s=>s.replace(n=/./g,c=>c.repeat(n[c]=-~n[c]))

Edit: Saved 3 bytes thanks to @user81655.

\$\endgroup\$
8
\$\begingroup\$

Haskell, 50 42 41 bytes

Saved 8 bytes thanks to Lynn

f t=[c|(i,c)<-zip[1..]t,x<-take i t,c==x]
\$\endgroup\$
  • 1
    \$\begingroup\$ How about: f t=[c|(i,c)<-zip[0..]t,j<-[0..i],c==t!!j] \$\endgroup\$ – Lynn Apr 4 '16 at 12:23
8
\$\begingroup\$

MATL, 8 bytes

tt!=RsY"

Try it online! Or verify all test cases at once.

Explanation

t    % take input string implictly. Duplicate
t!   % duplicate and transpose into a column
=    % test for equality with broadcast. Gives an NxN array, where N is
     % input string length
R    % upper triangular part: set entries below the diagonal to 0
s    % sum of each column. For each postion in the input, gives how many
     % times that letter has appeared up to that position
Y"   % replicate elements (run-length decoding). Display implicitly
\$\endgroup\$
8
\$\begingroup\$

Labyrinth, 54 25 bytes

<#; "#: ={},>
 }=}(.);("@

Another collab with @MartinBüttner, who actually did most almost all of the golfing for this one. By revamping the algorithm, we've managed to cut down the program size by quite a bit!

Try it online!

Explanation

A quick Labrinth primer:

  • Labyrinth is a stack-based 2D language. There are two stacks, a main and auxiliary stack, and popping from an empty stack yields zero.

  • At each junction, where there are multiple paths for the instruction pointer to move down, the top of the main stack is checked to see where to go next. Negative is turn left, zero is straight ahead and positive is turn right.

The two stacks of arbitrary-precision integers isn't much flexibility in terms of memory options. To perform the counting, this program actually uses the two stacks as a tape, with shifting a value from one stack to the other being akin to moving a memory pointer left/right by a cell. It's not quite the same as that though, since we need to drag a loop counter with us on the way up.

enter image description here

First off, the < and > on either end pop an offset and rotate the row of code that offset away by one either left or right. This mechanism is used to make the code run in a loop - the < pops a zero and rotates the current row left, putting the IP at the right of the code, and the > pops another zero and fixes the row back.

Here's what happens each iteration, in relation to the diagram above:

[Section 1]
,}    Read char of input and shift to aux - the char will be used as a counter
      to determine how many elements to shift

[Section 2 - shift loop]
{     Shift counter from aux
"     No-op at a junction: turn left to [Section 3] if char was EOF (-1), otherwise
      turn right
(     Decrement counter; go forward to [Section 4] if zero, otherwise turn right
=     Swap tops of main and aux - we've pulled a value from aux and moved the
      decremented counter to aux, ready for the next loop iteration

[Section 3]
@     Terminate

[Section 4]
;     Pop the zeroed counter
)     Increment the top of the main stack, updating the count of the number of times
      we've seen the read char
:     Copy the count, to determine how many chars to output

[Section 5 - output loop]
#.    Output (number of elements on stack) as a char
(     Decrement the count of how many chars to output; go forward to [Section 6]
      if zero, otherwise turn right
"     No-op

[Section 6]
}     Shift the zeroed counter to aux

[Section 7a]
This section is meant to shift one element at a time from main to aux until the main
stack is empty, but the first iteration actually traverses the loop the wrong way!

Suppose the stack state is [... a b c | 0 d e ...].

=     Swap tops of main and aux               [... a b 0 | c d e ...]
}     Move top of main to aux                 [... a b | 0 c d e ...]
#;    Push stack depth and pop it (no-op)
=     Swap tops of main and aux               [... a 0 | b c d e ...]
      Top is 0 at a junction - can't move
      forwards so we bounce back
;     Pop the top 0                           [... a | b c d e ... ]

The net result is that we've shifted two chars from main to aux and popped the
extraneous zero. From here the loop is traversed anticlockwise as intended.

[Section 7b - unshift loop]

#     Push stack depth; if zero, move forward to the <, else turn left
}=    Move to aux and swap main and aux, thus moving the char below (stack depth)
      to aux
;     Pop the stack depth
\$\endgroup\$
7
\$\begingroup\$

Perl, 17

(16 bytes code, +1 for -p)

s/./${$&}.=$&/ge

Usage:

perl -pe 's/./${$&}.=$&/ge' <<< 'bonobo'
bonoobbooo
\$\endgroup\$
7
\$\begingroup\$

Pyth, 7 bytes

s@Led._

Test suite

Test suite thanks to DenkerAffe

Explanation:

s@Led._
     ._    All prefixes, implicitly applied to the input.
 @L        Filter each prefix for characters equal to
   ed      the last character of the prefix
s          Concatenate and implicitly print.
\$\endgroup\$
6
\$\begingroup\$

Python 3, 52

def f(s):*s,x=s;return s and f(s)+x+x*s.count(x)or x
\$\endgroup\$
  • 4
    \$\begingroup\$ Ah, going from the end makes so much more sense! You can do this shorter in a lambda, without the need for Python 3 specifically: f=lambda s:s and f(s[:-1])+s[-1]*s.count(s[-1]) \$\endgroup\$ – Sp3000 Apr 4 '16 at 13:11
  • \$\begingroup\$ I though it could be done that way. But I don't like subscripting in Python :P \$\endgroup\$ – pacholik Apr 4 '16 at 13:19
5
\$\begingroup\$

PowerShell v2+, 52 47 bytes

$b=@{};-join([char[]]$args[0]|%{"$_"*++$b[$_]})

Constructs an empty hashtable, stores it in $b. This is our "counter" of what letters we've seen. We then take input $args[0], cast it as a char-array, and send it through a loop. Each iteration, we take the current character "$_" and multiply it by the pre-incremented counter at the given value, which will make the first occurrence be multiplied by 1, the second by 2 and so on. We encapsulate that with a -join so it's all one word being output.

Saved 5 bytes thanks to TessellatingHeckler by using a hashtable instead of an array, so we didn't need to decrement the ASCII character by 97 to reach the appropriate index. This works because pre-incrementing the hash index implicitly calls .Add() in the background if that index doesn't exist, since hashtables are mutable.

PS C:\Tools\Scripts\golfing> .\stretch-the-word.ps1 tessellatingheckler
tessseelllattingheeeckllleeeer
\$\endgroup\$
  • \$\begingroup\$ @TessellatingHeckler Indeed - thanks! \$\endgroup\$ – AdmBorkBork Apr 8 '16 at 12:28
5
\$\begingroup\$

Dyalog APL, 6 bytes

∊,\∩¨⊢

TryAPL!

4 functions is an atop (2-train) of a fork (3-train):

┌──┴──┐  
∊ ┌───┼─┐
  \   ¨ ⊢
┌─┘ ┌─┘  
,   ∩    

First (right – a no-op) on the given string, giving 'bonobo'

Then ,\ (concatenation scan) on the string, giving 'b' 'bo' 'bon' 'bono' 'bonob' 'bonobo'

The two are forked together with (given as right and left arguments to) ∩¨ (intersection each), i.e. ('b'∩'b') ('bo'∩'o') ('bon'∩'n') ('bono'∩'o') ('bonob'∩'b') ('bonobo'∩'o'), which is 'b' 'o' 'n' 'oo' 'bb' 'ooo'

Finally, (enlist) is applied to the result to flatten it, giving 'bonoobbooo'

Hey, at least it matches Pyth! Obviously Jelly is shorter as it is a golf version of J, which in turn is an advanced 2-character-per-function dialect of APL.

\$\endgroup\$
4
\$\begingroup\$

Pyth, 11 bytes

s.e*b/<Qhkb

Try it here!

Explanation

s.e*b/<Qhkb    # Q = input

 .e            # map over input with b as value and k as index (Q get appended at the end inplicitly)
      <Qhk     # take the first k+1 chars of Q
     /    b    # count occurences of b in there
   *b          # repeat b that many times
s              # join resulting list into one string
\$\endgroup\$
4
\$\begingroup\$

J, 11 bytes

#~+/@(={:)\

This is a monadic verb. Try it here. Usage:

   f =: #~+/@(={:)\
   f 'tutu'
'tuttuu'

Explanation

#~+/@(={:)\
     (   )\  For each non-empty prefix:
       {:      Take last element,
      =        compare for equality to the others and itself
  +/@          and take sum (number of matches).
#~           Replicate original elements wrt the resulting array.
\$\endgroup\$
4
\$\begingroup\$

05AB1E, 10 bytes

Code:

$vy«Dy¢y×?

Explanation:

$           # Push the number 1 and input
 v          # Map over the input string
  y«        # Concat the letter to the previous string (initial 1)
    D       # Duplicate this string
     y¢     # Count the occurences of the current character in the string
       y×   # Multiply this number with the current character
         ?  # Pop and print without a newline

Uses the CP-1252 encoding. Try it online!

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

CJam, 14

q:A,{)A<_)--}/

Try it online

Explanation:

q:A      read the input and store in A
,        get the string length
{…}/     for each number from 0 to length-1
  )      increment the number
  A<     get the prefix of A with that length
  _      duplicate it
  )      separate the last character
  -      remove it from the rest of the prefix
  -      remove all the remaining characters (different from the last one)
          from the prefix
\$\endgroup\$
2
\$\begingroup\$

Perl 6, 37 bytes

{.split('').map({$_ x++%.{$_}}).join}
\$\endgroup\$
2
\$\begingroup\$

><>, 52 bytes

i:0(?;&l:?!v1-$:&:&=?\}70.>
6f+0.00o:&~/         \:o

It stacks every letter read, prints them once and once again for every similar letter in the stack.
It uses the & register, because having to handle 3 variables on the stack (current read letter, position in the stack, letter at this position) is a pain.

You can try it here!

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

Rust, 176 Bytes

fn s(w:&str)->String{let mut m=std::collections::HashMap::new();w.chars().map(|c|{let mut s=m.remove(&c).unwrap_or(String::new());s.push(c);m.insert(c,s.clone());s}).collect()}

This uses a map to store a string for every character in the input. For each character, the string will be removed from the map, concatenated with the character, inserted back into the map and appended to the output.

I would have liked to use get(...) instead of remove(...), but the borrow checker had me change my mind.

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

Mathcad, 66 bytes

Unfortunately, Mathcad doesn't have particularly good string handling, so I've converted the input string to a vector and then used a (character code indexed) vector to keep track of the number of times a character is encountered, adding the character that number of times to a result vector. Finally, the result vector is converted back to a string. Quite lenghty unfortunately.

enter image description here

Note that Mathcad uses a 2D "whiteboard" interface, with a mix of normal text and operators; operators are normally entered via a toolbar or keyboard shortcut; for example, ctl-# enters the for loop operator, which comprises the keyword for, the element-of symbol and 3 empty "placeholders" for the iteration variable, range and body expressions respectively. Typing [ after a variable name enters array index mode, Typing ' enters a matched pair of parentheses (mostly ... there are exceptions depending upon what else is in the surrounding expression)

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

Javascript ES6 44 bytes

q=>q.replace(/./g,a=>x[a]=(x[a]||'')+a,x=[])

old answer

Javascript ES6 46 bytes

q=>(x=[...q]).map(a=>x[a]=(x[a]||'')+a).join``

//thanks user81655 for -1 byte
\$\endgroup\$
  • 1
    \$\begingroup\$ You could save a byte by moving x to the input array -> q=>(x=[...q]).map(a=>x[a]=(x[a]||'')+a).join`` \$\endgroup\$ – user81655 Apr 8 '16 at 4:03
2
\$\begingroup\$

Julia, 38 35 bytes

!s=[]==s?s:[!s[1:end-1];s∩s[end]]

I/O is in the from of character arrays. Try it online!

How it works

We (re)define the monadic operator ! for our purposes.

When ! is called, it checks if its argument s is empty. If it is, it returns its argument.

If s is non-empty, we intersect s with its last character (s[end]), which yields all occurrences of that character in s. This result is concatenated with the return value of a recursive call to ! with s minus its last character (s[1:end-1]) as argument.

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

PHP, 54 51 50 47 bytes

for(;$C=$argn[$X++];)echo str_repeat($C,++$$C);

Run like this:

echo abracadabra | php -nR 'for(;$C=$argn[$X++];)echo str_repeat($C,++$$C); echo"\n";'

Tweaks

  • Saved 3 bytes by using variable variables. Changed used variables to uppercase to prevent collision
  • Saved a byte by removing type cast null to int for string offset, as string offset is cast to int anyway
  • Saved 3 bytes by using $argn instead of $argv (thx Titus)
\$\endgroup\$
  • \$\begingroup\$ Use $argn with -R to save three more bytes. \$\endgroup\$ – Titus May 2 '18 at 8:41
  • \$\begingroup\$ Oh, and -n should do the same as your -d error_reporting: n stands for no config file, and notices are off in the default config; so -nr (respectively -nR) should suffice. \$\endgroup\$ – Titus May 2 '18 at 8:57
  • \$\begingroup\$ @Titus 2 year old answer, but thx anyway :) \$\endgroup\$ – aross May 2 '18 at 9:20
1
\$\begingroup\$

Mathematica, 57 bytes

StringReplace[Clear@c;c@_=0;#,x_:>x~StringRepeat~++c[x]]&

We use c[x] as a lookup table of how often character x has already occurred. This is incremented each time it's retrieved in x~StringRepeat~++c[x]. Unfortunately, to make the function reusable, we need to reset the lookup table each time with Clear@c;c@_=0;, which is quite expensive.

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

awk, 72 bytes

BEGIN{FS=""}{for(i=1;i<=NF;i++){a[$i]++;for(j=0;j<a[$i];j++)printf $i}}

The idea is to store the count of the appearing character in an associative array and print the character this count times.

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

Beam, 32 33 42 bytes

This should have been smaller, but I lost some bytes initializing the memory slots to 0. Swapping some flow directions managed to eliminate a lot of empty space.

 >+\
vus/
>rnH
  >g'\
(@v's/
^`<

Try it in this snippet

General explanation.

  • Set all the memory slots from 0-255 to 0
  • Read in the input ascii value into the beam
  • If beam is 0 halt (beam = store)
  • Get the memory[beam] value into the store, increment it and save back
  • Decrement the store to 0 printing out the beam character
  • Repeat
\$\endgroup\$
1
\$\begingroup\$

Python, 66 62 bytes

Try it here

Golfed

def s(w,o=[],n=""):
 for x in w:o+=x;n+=x*o.count(x)
 return n

Ungolfed

def stretch(word):
    occurrences = []
    newWord = ""
    for w in word:
        occurrences.append(w)
        newWord += w * occurrences.count(w)
    return newWord
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.