39
\$\begingroup\$

Write a program or function that duplicates letters in a word, so that all the duplicated letters arranged from left to right in the word would form the input array.

For example:

input: chameleon, [c,a,l,n]
output: cchaamelleonn

Input

  • The starting word (e.g. chameleon)
  • An array of characters ([c,a,l,n]) or a string to represent an array (caln), or something similar
  • Input can be through function parameters, STDIN or language equivalents
  • All inputs will be lower-case letters (a-z)

Output

  • The changed word

  • If there are multiple solutions, any can be printed

    input: banana [n,a]  
    possible outputs: bannaana, banannaa
                         |-|---------|-|--->[n,a]
    
  • You may assume that the input word (not necessarily the array) will have the letters in the array (in order)

  • You may also assume that the inputs have no consecutive letters which are the same (NOT apple, geek, green, glass, door...)

Examples

input: abcdefghij, [a,b,c]
output: aabbccdefghij

input: lizard, [i,a,r,d]
output: liizaarrdd

input: coconut, [c,o]
ouput: ccooconut or coccoonut or ccocoonut

input: onomatopoeia, [o,o,a,o,o]
output: oonoomaatoopooeia

input: onomatopoeia, [o,a,o]
output: oonomaatoopoeia or onoomaatoopoeia or oonomaatopooeia etc.

Shortest program wins!

Leaderboard (thanks to Martin Büttner for the snippet)

/* Configuration */

var QUESTION_ID = 51984; // Obtain this from the url
// It will be like http://XYZ.stackexchange.com/questions/QUESTION_ID/... on any question page
var ANSWER_FILTER = "!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe";

/* App */

var answers = [], page = 1;

function answersUrl(index) {
  return "http://api.stackexchange.com/2.2/questions/" +  QUESTION_ID + "/answers?page=" + index + "&pagesize=100&order=desc&sort=creation&site=codegolf&filter=" + ANSWER_FILTER;
}

function getAnswers() {
  jQuery.ajax({
    url: answersUrl(page++),
    method: "get",
    dataType: "jsonp",
    crossDomain: true,
    success: function (data) {
      answers.push.apply(answers, data.items);
      if (data.has_more) getAnswers();
      else process();
    }
  });
}

getAnswers();

var SIZE_REG = /\d+(?=[^\d&]*(?:<(?:s>[^&]*<\/s>|[^&]+>)[^\d&]*)*$)/;
var NUMBER_REG = /\d+/;
var LANGUAGE_REG = /^#*\s*([^,]+)/;

function shouldHaveHeading(a) {
  var pass = false;
  var lines = a.body_markdown.split("\n");
  try {
    pass |= /^#/.test(a.body_markdown);
    pass |= ["-", "="]
              .indexOf(lines[1][0]) > -1;
    pass &= LANGUAGE_REG.test(a.body_markdown);
  } catch (ex) {}
  return pass;
}

function shouldHaveScore(a) {
  var pass = false;
  try {
    pass |= SIZE_REG.test(a.body_markdown.split("\n")[0]);
  } catch (ex) {}
  return pass;
}

function getAuthorName(a) {
  return a.owner.display_name;
}

function process() {
  answers = answers.filter(shouldHaveScore)
                   .filter(shouldHaveHeading);
  answers.sort(function (a, b) {
    var aB = +(a.body_markdown.split("\n")[0].match(SIZE_REG) || [Infinity])[0],
        bB = +(b.body_markdown.split("\n")[0].match(SIZE_REG) || [Infinity])[0];
    return aB - bB
  });

  var languages = {};
  var place = 1;
  var lastSize = null;
  var lastPlace = 1;
  answers.forEach(function (a) {
    var headline = a.body_markdown.split("\n")[0];
    //console.log(a);
    var answer = jQuery("#answer-template").html();
    var num = headline.match(NUMBER_REG)[0];
    var size = (headline.match(SIZE_REG)||[0])[0];
    var language = headline.match(LANGUAGE_REG)[1];
    var user = getAuthorName(a);
    if (size != lastSize)
      lastPlace = place;
    lastSize = size;
    ++place;
    answer = answer.replace("{{PLACE}}", lastPlace + ".")
                   .replace("{{NAME}}", user)
                   .replace("{{LANGUAGE}}", language)
                   .replace("{{SIZE}}", size)
                   .replace("{{LINK}}", a.share_link);
    answer = jQuery(answer)
    jQuery("#answers").append(answer);

    languages[language] = languages[language] || {lang: language, user: user, size: size, link: a.share_link};
  });

  var langs = [];
  for (var lang in languages)
    if (languages.hasOwnProperty(lang))
      langs.push(languages[lang]);

  langs.sort(function (a, b) {
    if (a.lang > b.lang) return 1;
    if (a.lang < b.lang) return -1;
    return 0;
  });

  for (var i = 0; i < langs.length; ++i)
  {
    var language = jQuery("#language-template").html();
    var lang = langs[i];
    language = language.replace("{{LANGUAGE}}", lang.lang)
                       .replace("{{NAME}}", lang.user)
                       .replace("{{SIZE}}", lang.size)
                       .replace("{{LINK}}", lang.link);
    language = jQuery(language);
    jQuery("#languages").append(language);
  }

}
body { text-align: left !important}

#answer-list {
  padding: 10px;
  width: 50%;
  float: left;
}

#language-list {
  padding: 10px;
  width: 50%px;
  float: left;
}

table thead {
  font-weight: bold;
}

table td {
  padding: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b">
<div id="answer-list">
  <h2>Leaderboard</h2>
  <table class="answer-list">
    <thead>
      <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr>
    </thead>
    <tbody id="answers">

    </tbody>
  </table>
</div>
<div id="language-list">
  <h2>Winners by Language</h2>
  <table class="language-list">
    <thead>
      <tr><td>Language</td><td>User</td><td>Score</td></tr>
    </thead>
    <tbody id="languages">

    </tbody>
  </table>
</div>
<table style="display: none">
  <tbody id="answer-template">
    <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr>
  </tbody>
</table>
<table style="display: none">
  <tbody id="language-template">
    <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr>
  </tbody>
</table>

\$\endgroup\$
12
  • \$\begingroup\$ @AlexA. only one instance because otherwise the array formed by the duplicate letters would be [c,o,c,o], rather than [c,o]. \$\endgroup\$ Commented Jun 22, 2015 at 16:03
  • \$\begingroup\$ Yeah sorry, reading it again that's obvious. Thanks. \$\endgroup\$
    – Alex A.
    Commented Jun 22, 2015 at 16:08
  • 2
    \$\begingroup\$ Seeing this got quite a lot of answers, and many in the same languages, would you be interested in adding the leaderboard snippet? If so, I'm happy to edit it in and amend the answers that don't use the required header format. \$\endgroup\$ Commented Jun 23, 2015 at 13:12
  • \$\begingroup\$ @MartinBüttner I forgot about that! Added. I had to change #answer-list and #language-list width to 50% to avoid overlapping columns in your snippet. \$\endgroup\$ Commented Jun 23, 2015 at 20:49
  • 1
    \$\begingroup\$ Clarification (see my bash+sed answer): Is it illegal for banana, na => baannana? I believed that "You may assume that all inputs will have the letters in the array (in order)" is meant to permit, but not require, answers to process both lists sequentially, but @manatwork interpreted it differently. \$\endgroup\$ Commented Jun 24, 2015 at 12:48

40 Answers 40

44
\$\begingroup\$

Brainfuck, 46 45 (63 with printable characters in input)

Compatible with Alex Pankratov's bff (brainfuck interpreter used on SPOJ and ideone) and Thomas Cort's BFI (used on Anarchy Golf).

The printable version takes the array first as a string, followed by a tab, followed by the starting string with no trailing newline.

Demonstration on ideone.

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

We can save some bytes by using \x00 as a separator instead of tab:

,[>,]
<[<]
<,+
[
  -.
  [>+>-<<-]
  >>
  [
    <[>+<-]
  ]
  <[.[-]]
  ,+
]
\$\endgroup\$
3
  • 24
    \$\begingroup\$ That feeling when BF is shorter than my Python code.. :( \$\endgroup\$
    – Kade
    Commented Jun 22, 2015 at 15:24
  • 7
    \$\begingroup\$ I usually don't care for Brainfuck, but this is awesome! \$\endgroup\$
    – Dennis
    Commented Jun 22, 2015 at 15:41
  • \$\begingroup\$ This is beautiful. \$\endgroup\$
    – Sarima
    Commented Jun 23, 2015 at 7:45
14
\$\begingroup\$

CJam, 15 bytes

rr{_C#)/(C@s}fC

Try it online.

How it works

rr              e# Read two whitespace-separated tokens from STDIN.
  {         }fC e# For each character C in the second string.
   _            e#   Duplicate the first string.
    C#          e#   Compute the index of the character in the string.
      )/        e#   Add 1 and split the string in slice of that size.
        (       e#   Shift out the first slice.
         C      e#   Push the character.
          @     e#   Rotate the remainder of the string in top of the stack.
           s    e#   Stringify (concatenate the slices).
\$\endgroup\$
3
  • \$\begingroup\$ It's a battle of the CJams! You and Sp both have 15 byte CJam answers, and 15 is currently the shortest. :) \$\endgroup\$
    – Alex A.
    Commented Jun 22, 2015 at 16:13
  • 3
    \$\begingroup\$ @AlexA. Just wait for Pyth. You just wait... \$\endgroup\$
    – Sp3000
    Commented Jun 22, 2015 at 16:18
  • 2
    \$\begingroup\$ Sounds like you'd better learn Pyth. ;) \$\endgroup\$
    – Alex A.
    Commented Jun 22, 2015 at 17:19
12
\$\begingroup\$

C, 62 bytes

f(char*s,char*c){while(*s-*c||putchar(*c++),*s)putchar(*s++);}

Well, this is surprisingly competetive.

We define a function f(char*, char*) that takes the string as its first input and the array of characters to duplicate as its second input.

Some testing code:

int main (int argc, char** argv) {
    f("onomatopeia", "oao");
    return 0;
}

Which prints:

oonomaatoopeia

Try it online!

If it is acceptable to submit a macro rather than a function, the following #define g(s,c) is just 58 bytes, but requires s and c to be actual pointers:

#define g(s,c)while(*s-*c||putchar(*c++),*s)putchar(*s++);
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Thanks for making me look up the comma operator. That's useful! \$\endgroup\$
    – Oliphaunt
    Commented Jun 23, 2015 at 10:45
  • \$\begingroup\$ Suggest write(1,c++,*s==*c) instead of *s-*c||putchar(*c++) \$\endgroup\$
    – ceilingcat
    Commented Sep 21, 2020 at 23:03
11
\$\begingroup\$

CJam, 15 bytes

rr{:X/(XX+@X*}/

An alternative CJam approach. Try it online

Explanation

For each character in the second string, we do two things.

  1. Split the current suffix of the string by the character, e.g. "beeper" "e" -> ["b" "" "p" "r"]

  2. Uncons the first string in the array, insert two of the character, then rejoin the rest of the array with the character, e.g. "b" "ee" "eper". The last string is the new suffix.

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

Python, 61

def f(s,l):b=s[:1]==l[:1];return s and-~b*s[0]+f(s[1:],l[b:])

A greedy recursive solution. Saves to b whether the first letter of the string s is the first letter of the string l of letters to double. If so, take one of that letter and prepend it to the recursive call with the rest of s, removing the first element from l. If not b, do the same but don't double the letter and don't remove from l.

The code checks s[:1]==l[:1] rather than s[0]==l[0] to avoid an index-out-of-bounds error when s or l is empty.

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

Retina, 33 bytes

More information about Retina.

+`(?=(.))(((.)(?<!\4.))+\n)\1
$1$2

This expects the two strings on STDIN, separated by a newline.

For counting purposes, each line goes into a separate file, \n should be replaced with an actual newline character (0x0A). If you actually want to test this, it's more convenient to put this in a single file where \n remains as it is and then invoke Retina with the -s option before passing the file.

Explanation

(Outdated... I managed to get rid of the marker... I'll update this later.)

Each pair of lines is a regex substitution (first line the pattern, second line the substitution).

^
#

This puts a # as a marker at the start of the input string.

+`#(.*?(.))(.*\n)\2
$1$2#$3

This finds the first letter in the input (after the marker) corresponding to the next letter to be duplicated, duplicates that letter, moves the marker behind it, and drops the first character of the second string. The +` at the front tells Retina to do this repeatedly until the string stops changing (in this case, because the second string is empty and all required letters have been duplicated).

#
<empty>

Finally, we clean up the string by dropping the marker.

\$\endgroup\$
5
  • 2
    \$\begingroup\$ I figured that retina would have a nice solution, and I was right, because you found one. Also, when I first skimmed your description, I read the end as "we clean up the string by dropping the mic." \$\endgroup\$
    – mbomb007
    Commented Jun 22, 2015 at 19:28
  • \$\begingroup\$ @mbomb007 I was hoping to get rid of the "mic" by only duplicating individual letters that don't have any duplicates after them, but I can't do it in less than 33 bytes. (There's a broken 28 byte version in the revision history.) \$\endgroup\$ Commented Jun 22, 2015 at 19:33
  • \$\begingroup\$ @mbomb007 FYI, I did manage to remove the marker now, but the byte count is still the same. This still looks golfable though. \$\endgroup\$ Commented Jun 23, 2015 at 12:19
  • \$\begingroup\$ As an aside, I just realized that Retina doesn't have a page on esolangs.org \$\endgroup\$
    – mbomb007
    Commented Jun 23, 2015 at 14:55
  • \$\begingroup\$ @mbomb007 Yes, I'm aware. I'll probably add one after I've implemented a few of the more important outstanding features. \$\endgroup\$ Commented Jun 23, 2015 at 15:44
7
\$\begingroup\$

Prolog, 95 83 79 56 bytes

d([A|S],H):-put(A),H=[A|T],put(A),d(S,T);d(S,H).
d(_,_).

Example:

d(`chameleon`,`caln`).

returns

cchaamelleonn

Edit: Saved 4 bytes thanks to Oliphaunt

Edit2: Saved 20 bytes using the deprecated put/1 SWI-Prolog predicate instead of writef. Saved one byte replacing the recursion end predicate d([],_). to d(_,_).. Won't work if the ordering of the two definitions of d is swapped though, but we don't care about that in golfed code. Saved another 2 bytes removing the parenthesis around H=[A|T],put(A),d(S,T)

\$\endgroup\$
3
  • 1
    \$\begingroup\$ I'm not really sure why this got downvoted. Maybe add some explanation to your code? \$\endgroup\$
    – Alex A.
    Commented Jun 22, 2015 at 15:54
  • 1
    \$\begingroup\$ You can save four bytes by unifying implicitly: H=[A|T]. Also, why not make it a little more readable by replacing the spaces with newlines? \$\endgroup\$
    – Oliphaunt
    Commented Jun 23, 2015 at 10:56
  • \$\begingroup\$ @Oliphaunt Thanks for the suggestion, I didn't see this slight optimization after I originally modified my code to use the H=[A|T] clause. \$\endgroup\$
    – Fatalize
    Commented Jun 23, 2015 at 11:35
6
\$\begingroup\$

Python 2, 83 74 72 65 Bytes

No real special tricks here. x is the string, y is the array of characters that are duplicated. To clarify if this doesn't copy properly, the first indentation level is a space, the next is a tab.

Edit 1: Saved 9 bytes by using string manipulation instead of pop().

Edit 2: Saved 2 bytes by using -~ to increment g by 1.

Edit 3: Saved 7 bytes by using y[:1] trick, thanks to xnor for this!

def f(x,y,s=''):
 for c in x:g=y[:1]==c;s+=c*-~g;y=y[g:]
 print s

Check it out here.

Properly formatted and explained:

def f(x,y,s=''):           # Defining a function that takes our input,
                           # plus holds a variable we'll append to.
  for c in x:              # For every character in 'x', do the following:
    g = y[:1] == c         # Get the first element from the second string, will
                           # return an empty string if there's nothing left.
                           # Thanks to xnor for this trick!
    s += c * -~g           # Since int(g) would either evaluate to 0 or 1, we
                           # use the -~ method of incrementing g to multiply
                           # the character by 1 or 2 and append it to 's'
    y = y[g:]              # Again, since int(g) would either evaluate to 0
                           # or 1, use that to cut the first value off y, or
                           # keep it if the characters didn't match.
  print s                  # Print the string 's' we've been appending to.
\$\endgroup\$
5
  • \$\begingroup\$ "You may assume that all inputs will have the letters in the array (in order)." That should save you quite a few bytes. \$\endgroup\$
    – mbomb007
    Commented Jun 22, 2015 at 19:49
  • 2
    \$\begingroup\$ You can get the first element from a possibly-empty string as y[:1]. \$\endgroup\$
    – xnor
    Commented Jun 22, 2015 at 20:37
  • \$\begingroup\$ I now realize that you can't save as many as I thought because of how you're doing it with y=y[g:], so "quite a few" is quite an exaggeration. \$\endgroup\$
    – mbomb007
    Commented Jun 22, 2015 at 20:42
  • \$\begingroup\$ @Vioz- I was thinking y[:1]==c. Does that work? \$\endgroup\$
    – xnor
    Commented Jun 22, 2015 at 20:46
  • \$\begingroup\$ @xnor Yes, it does if I take the letters that need replacing instead. Thanks! \$\endgroup\$
    – Kade
    Commented Jun 22, 2015 at 20:47
5
\$\begingroup\$

Pyth, 14 bytes

s+L&@d<Q1.(QZz

Demonstration.

Input style:

banana
["b","a","n","a"]

Explanation:

s+L&@d<Q1.(Q0z
                  Implicit: z = input(); Q = eval(input())
 +L          z    Map (lambda d) over z, adding the result to each character.
    @d<Q1         Intersection of d with Q[:1], up to the first element of Q.
   &              Logical and - if the first arg is truthy, evaluate and
                  return the second arg, otherwise return first arg.
         .(Q0     Q.pop(0)
                  The addition will either be the empty string, for the empty
                  intersection, or the character that was Q[0] otherwise.

s                 Concatenate and print.
\$\endgroup\$
5
\$\begingroup\$

Excel VBA, 110 bytes

This is my first entry to CodeGolf so I hope this is ok.

You enter the input word in A1 and then the letters to be replaced in B1 and the resulting word is displayed in a message box.

w = Cells(1, 1)
l = Cells(2, 1)
For i = 1 To Len(w)
x = Left(w, 1)
R = R + x
If InStr(l, x) > 0 Then
R = R + x
End If
w = Right(w, Len(w) - 1)
Next
MsgBox R
\$\endgroup\$
5
  • 2
    \$\begingroup\$ If VBA isn't indentation-sensitive, you could get rid of all of the indents and save a few bytes. I think you can also get rid of all of the spaces after commas and around operators. Ought to save you a few bytes. \$\endgroup\$
    – anon
    Commented Jun 23, 2015 at 14:05
  • \$\begingroup\$ @QPaysTaxes Thanks for your edit. I pressed rollback just to see what it would do. Not sure if that made you lose points or something for your edit? \$\endgroup\$ Commented Jun 23, 2015 at 14:16
  • \$\begingroup\$ Nope, I still have the +2, though I did get confused for a bit. You might want to roll back again; at least according to three highish-rep people, it was a good edit. \$\endgroup\$
    – anon
    Commented Jun 23, 2015 at 14:16
  • \$\begingroup\$ @QPaysTaxes I agree I liked the edit. Think I just rolledbacked one too many times. \$\endgroup\$ Commented Jun 23, 2015 at 14:18
  • \$\begingroup\$ I can't tell. Mobile doesn't exactly display things nicely. Ultimately, though, what matters is the code, not the formatting. \$\endgroup\$
    – anon
    Commented Jun 23, 2015 at 14:21
4
\$\begingroup\$

Haskell, 42 bytes

(a:b)#e@(c:d)|a==c=a:a:b#d|1<2=a:b#e
a#_=a

Usage example:

*Main> "coconut" # "co"
"ccooconut"
*Main> "lizard" # "iard"
"liizaarrdd"
*Main> "onomatopoeia" # "ooaoo"
"oonoomaatoopooeia"

How it works:

If one string is empty, the result is the first string. Else: if the first characters of the strings match, take it two times and append a recursive call with the tails of the strings. If the characters don't match, take the first character of the first string and append a recursive call with the tail of the first string and the same second string.

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

Pyth, 18 17 bytes

sm?+d.(QZqd&QhQdz

Live demo.

Saved 1 byte thanks to @Jakube.

Explanation:

                z  Read the first line of input.
 m                 For each character in that line
  ?      qd&QhQ    If (?) the first char of the stretch list (`&QhQ`) 
                   and the current character are equal,
   +d.(QZ          Then double the current character and pop an element off
                   the stretch list.
               d   Otherwise, just return the same character.
s                  Join all the characters together.

Original version:

jkm?+d.(QZqd&QhQdz

Live demo for original.

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

Javascript, 47 bytes

(a,b)=>a.replace(/./g,d=>b[0]!=d?d:d+b.shift())

Taking advantage of some ES6 features.

\$\endgroup\$
8
  • 1
    \$\begingroup\$ Does this work correctly for onomatopoeia, oao? \$\endgroup\$
    – Alex A.
    Commented Jun 22, 2015 at 17:34
  • 1
    \$\begingroup\$ @AlexA. Outputs: "oonoomaatoopooeiaa". Ah, I understand. Will fix \$\endgroup\$
    – Cereal
    Commented Jun 22, 2015 at 17:42
  • \$\begingroup\$ Fixed, I think. Added a lot of characters :( \$\endgroup\$
    – Cereal
    Commented Jun 22, 2015 at 17:54
  • \$\begingroup\$ Instead of b.indexOf(d)==0, try ~b.search(d) \$\endgroup\$ Commented Jun 22, 2015 at 17:55
  • \$\begingroup\$ @IsmaelMiguel search is only applicable on strings. Had to change b to an array \$\endgroup\$
    – Cereal
    Commented Jun 22, 2015 at 18:45
3
\$\begingroup\$

Pyth, 16 bytes

u|pH<GJxGH>GJwz

Try it online: Demonstration

This is quite hacky. Stack-based languages might have an advantage here.

Explanation

                   implicit: z = 1st input line, w = 2nd
u             wz   reduce, start with G = z
                   for each H in w, update G to:
        xGH          index of H in G
       h             +1
      J              store in J
    <GJ              substring: G[:J] (everything before index J)
  pH                 print substring then H (without newlines)
 |                   afterwards (actually or, but p always returns 0)
           >GJ       substring: G[J:] (everything from index J to end)
                     update G with ^
                   afterwards implicitly print the remainder G
\$\endgroup\$
3
  • \$\begingroup\$ @isaacg Help? There must be something shorter... \$\endgroup\$
    – Jakube
    Commented Jun 22, 2015 at 20:40
  • \$\begingroup\$ And more elegant ;-) \$\endgroup\$
    – Jakube
    Commented Jun 22, 2015 at 20:51
  • 1
    \$\begingroup\$ Got it in 14 - 1 less than CJam is the best place to be. \$\endgroup\$
    – isaacg
    Commented Jul 13, 2015 at 2:52
3
\$\begingroup\$

JavaScript ES6, 47 bytes

(w,s)=>w.replace(/./g,c=>c==s[0]?c+s.shift():c)

Assumes s is an array ["c","a","l","n"]

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

><> (Fish), 68 34 Bytes

ri&:o&:&=\
l&io& /!?/
?!;20.\l!\

You can run it at http://fishlanguage.com/playground inputting the string as the initial stack (with " marks, i.e. "chameleon") and the array of extra letters as the input stack (no " marks i.e. caln).

Don't forget to press the Give button to seed the input stack.

r       reverses the stack
i&      reads in the first input, and stores it in the register
:o      copies the top of the stack, and outputs the top of the stack
&:&     puts register value on stack, copies it, then puts top stack into register
=       checks if the top two values are equal, if yes push 1, else push 0
?       if top value is non-zero, execute next instruction
!       skips the following instruction (unless it was skipped by the previous ?)

If yes, then we proceed on the same line
&o      puts register value on stack, and outputs it
i&      reads in the first input, and stores it in the register
l       puts length of stack on stack, then proceed to lowest line

If no, we go directly to the last line
l       As above.
?!;     If zero value (from length), then end execution
20.     Push 2 and 0 onto stack, then pop top two values, and go to that position (2,0) (i.e. next instruction is at (3,0))

EDIT: Halved it! :)

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

REGXY, 24 bytes

Uses REGXY, a regex substitution based language. Input is assumed to be the starting word and the array, space separated (e.g. "chameleon caln").

/(.)(.* )\1| /\1\1\2/
//

The program works by matching a character in the first string with the first character after a space. If this matches, the character is repeated in the substitution and the character in the array is removed (well, not appended back into the string). Processing moves on to the second line, which is just a pointer back to the first line, which causes processing to repeat on the result of the previous substitution. Eventually, there will be no characters after the space, at which point the second branch of the alternation will match, removing the trailing space from the result. The regex will then fail to match, processing is completed and the result is returned.

If it helps, the iterative steps of execution are as follows:

chameleon caln
cchameleon aln
cchaameleon ln
cchaameleonn n
cchaameleonn  (with trailing space)
cchaameleonn

The program compiles and executes correctly with the sample interpreter in the link above, but the solution is perhaps a bit cheeky as it relies on an assumption in the vagueness of the language specification. The spec states that the first token on each line (before the /) acts as a label, but the assumption is that a null label-pointer will point back to the first command in the file with a null label (or in other words, that 'null' is a valid label). A less cheeky solution would be:

a/(.)(.* )\1| /\1\1\2/
b//a

Which amounts to 27 bytes

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

Japt -m, 10 7 bytes

iVvUèVÎ

Try it

iVvUèVÎ     :Implicit map of each character U in the first input (the string)
i           :Prepend
 V          :  The second input (the array)
  v         :  Remove this many elements from the start ...
   Uè       :    Count the occurrences in U of
     VÎ     :    The first element of V 
\$\endgroup\$
2
\$\begingroup\$

R, 119

Based on @Alex's answer, this one is a couple of bytes shorter:

function(s,a){message(unlist(lapply(strsplit(s,"")[[1]],function(x){if(length(a)&x==a[1]){a<<-a[-1];c(x,x)}else x})))}

Ungolfed:

function(s, a) {
  message(                             # Prints to output
    unlist(                            # Flattens list to vector
      lapply(                          # R's version of map
        strsplit(s,"")[[1]],           # Split vector to characters
        function (x) {
          if (length(a) & x == a[1]) { # If there are still elements in a
                                       # and there's a match
            a <<- a[-1]                # Modify a
            c(x, x)                    # And return the repeated character
          } else x                     # Otherwise just return it
        }
      )
    )
  )
}
\$\endgroup\$
2
\$\begingroup\$

Perl, 73 62 59 56

Entirely new approach yields much better results. Still, I bet it can be shorter.

Call as f('coconut', ['c','o']).

sub f{($s,$a)=@_;$s=~s/(.*?)($_)/\U$1$2$2/ for@$a;lc$s}

For each character in the array, find the first occurrence and duplicate it, and turn everything up to it to uppercase. Then return the entire string, converted to lowercase.

EDIT: shaved a couple of more characters by getting rid of shift and pop.


The previous version:

sub f{join '',map{shift @{$_[0]}if s/($_[0][0])/$1$1/;$_}split //,shift}
\$\endgroup\$
2
  • \$\begingroup\$ The new version doesn't respect the character order anymore. (BTW, “The foreach keyword is actually a synonym for the for keyword, so you can use either.” – Foreach Loops.) \$\endgroup\$
    – manatwork
    Commented Jun 24, 2015 at 16:02
  • \$\begingroup\$ @manatwork That should do it. And thanks for the for hint. It's actually shorter now. \$\endgroup\$
    – jja
    Commented Jun 24, 2015 at 16:20
2
\$\begingroup\$

Ruby, 52 47 bytes

Solution:

f=->(s,a){s.chars.map{|c|c==a[0]?a.shift*2:c}.join}

Example:

p f.call('banana', ['n','a']) # => "bannaana"

Explanation:

Proc form of a method which takes a string as the first argument, and an array of characters as the second argument. Maps a block onto an array of the characters in the string argument, which checks each character against first element of the comparison array, and if there is a match, removes the first element of the comparison array, and doubles it.


update

f=->s,a{s.chars.map{|c|c==a[0]?a.shift*2:c}*''}

\$\endgroup\$
1
  • \$\begingroup\$ You can skip the parentheses around the parameters s,a. And *'' is equivalent to .join. That's 5 bytes saved, but I still beat you by one (for now) :D \$\endgroup\$
    – daniero
    Commented Jun 23, 2015 at 19:41
1
\$\begingroup\$

JavaScript ES6, 72 bytes

(s,a,i=0,b=[...s])=>a.map(l=>b.splice(i=b.indexOf(l,i+2),0,l))&&b.join``

This is an anonymous function that takes 2 parameters: the starting word as a string and the characters to stretch as an array. Ungolfed code that uses ES5 and test UI below.

f=function(s,a){
  i=0
  b=s.split('')
  a.map(function(l){
    i=b.indexOf(l,i+2)
    b.splice(i,0,l)
  })
  return b.join('')
}

run=function(){document.getElementById('output').innerHTML=f(document.getElementById('s').value,document.getElementById('a').value.split(''))};document.getElementById('run').onclick=run;run()
<label>Starting word: <input type="text" id="s" value="onomatopoeia" /></label><br />
<label>Leters to duplicate: <input type="text" id="a" value="oao"/></label><br />
<button id="run">Run</button><br />Output: <output id="output"></output>

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

Python 2, 77

def f(x,y,b=''):
 for i in x:
    try:
     if i==y[0]:i=y.pop(0)*2
    except:0
    b+=i
 print b

Call as:

f('onomatopoeia',['o','a','o'])

I may have got the byte count horribly wrong... Uses a mixture of spaces and tabs.

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

rs, 39 bytes

More information about rs.

There's already a Retina answer, but I think this one uses a slightly different approach. They were also created separately: when I began working on this one, that answer hadn't been posted.

Besides, this one is 6 bytes longer anyway. :)

#
+#(\S)(\S*) ((\1)|(\S))/\1\4#\2 \5
#/

Live demo and test suite.

\$\endgroup\$
1
  • \$\begingroup\$ I really like that debug switch in your interpreter. \$\endgroup\$
    – Dennis
    Commented Jun 22, 2015 at 17:22
1
\$\begingroup\$

JavaScript, 92 characters

function f(s,c){r="";for(i=0;i<s.length;i++){r+=s[i];if(c.indexOf(s[i])>-1)r+=s[i]}return r}

Unobfuscated version:

function stretch(str, chars) {
    var ret = "";
    for(var i = 0; i < str.length; i++) {
        ret += str[i];
        if(chars.indexOf(str[i]) > -1) {
            ret += str[i];
        }
    }
    return ret;
}
\$\endgroup\$
1
\$\begingroup\$

R, 136 128 122 bytes

function(s,a){p=strsplit(s,"")[[1]];for(i in 1:nchar(s))if(length(a)&&(x=p[i])==a[1]){p[i]=paste0(x,x);a=a[-1]};message(p)}

This creates an unnamed function that accepts a string and a character vector as input and prints a string to STDOUT. To call it, give it a name.

Ungolfed + explanation:

f <- function(s, a) {
    # Split s into letters
    p <- strsplit(s, "")[[1]]

    # Loop over the letters of s
    for (i in 1:nchar(s)) {

        # If a isn't empty and the current letter is the first in a
        if (length(a) > 0 && p[i] == a[1]) {

            # Replace the letter with itself duplicated
            p[i] <- paste0(p[i], p[i])

            # Remove the first element from a
            a <- a[-1]
        }
    }

    # Combine p back into a string and print it
    message(p)
}

Examples:

> f("coconut", c("c","o"))
ccooconut

> f("onomatopoeia", c("o","a","o"))
oonomaatoopoeia

Saved 8 bytes thanks to MickeyT and another 3 thanks to jja!

\$\endgroup\$
4
  • \$\begingroup\$ You could use cat(p,sep='') to output straight to STDOUT for a couple \$\endgroup\$
    – MickyT
    Commented Jun 23, 2015 at 0:32
  • \$\begingroup\$ @MickyT: Didn't think of that! Thanks, edited. :) \$\endgroup\$
    – Alex A.
    Commented Jun 23, 2015 at 1:27
  • 1
    \$\begingroup\$ Actually, message(p) is shorter. \$\endgroup\$
    – jja
    Commented Jun 24, 2015 at 11:29
  • \$\begingroup\$ @jja: I didn't know about message, that's awesome! Thanks! Edited to use your suggestion. \$\endgroup\$
    – Alex A.
    Commented Jun 24, 2015 at 14:21
1
\$\begingroup\$

Perl, 51 bytes

$s=<>;$s=~s=^.*$_=$_=,$,.=$&for split"",<>;print$,;

Input is provided via STDIN. First input is the starting word (e.g. chameleon), second input is the letters as a single string (e.g. caln).

The above is just an obfuscated (read "prettier") way of doing the following:

$word = <>;
for $letter(split "", <>) {
   $word =~ s/^.*$letter/$letter/;
   $result .= $&;
}
print $result;

As we go through each letter, we replace from the start of the word up to the letter in the source word with just the new letter, and append the match (stored in $&) to our result. Since the match includes the letter and then gets replaced with the letter, each letter ends up appearing twice.

Because STDIN appends a new line character to both of our inputs, we're guaranteed to capture the remnants of the full word on the last match, i.e. the new line character.

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

Bash+sed, 51

sed "`sed 's/./s!^[^&]*&!\U\&&!;/g'<<<$1`s/.*/\L&/"

Input from stdin; characters to be doubled as a single argument:

$ echo chameleon | strtech caln
cchaamelleonn

This works by constructing a sed program from $2 and then executing it against $1. The sed program replaces the first occurrence of each replacement letter with two copies of its uppercase version, and downcases the whole lot at the end. For the example above, the generated sed program is

s!^[^c]*c!\U&C!;s!^[^a]*a!\U&A!;s!^[^l]*l!\U&L!;s!^[^n]*n!\U&N!;s/.*/\L&/

pretty-printed:

# if only sed had non-greedy matching...
s!^[^c]*c!\U&C!
s!^[^a]*a!\U&A!
s!^[^l]*l!\U&L!
s!^[^n]*n!\U&N!
s/.*/\L&/

I use the uppercase to mark characters processed so far; this avoids re-doubling characters that have already been doubled, or applying a doubling earlier than the previous one.

Earlier version, before clarification that order of replacement list is significant (44 chars):

sed "`sed 's/./s!&!\U&&!;/g'<<<$1`s/.*/\L&/"
\$\endgroup\$
4
  • \$\begingroup\$ Incorrect. strtech na <<< banana outputs “baannana”, but first an occurrence on “n” should be doubled, only after that an occurrence of “a”. \$\endgroup\$
    – manatwork
    Commented Jun 24, 2015 at 11:04
  • \$\begingroup\$ In that case, I've misunderstood the question; it wasn't explicit that the ordering meant that prior letters should not be doubled, simply that you would be able to find a subsequent one to double. I'll have a think about an alternative that satisfies this new requirement. \$\endgroup\$ Commented Jun 24, 2015 at 11:45
  • \$\begingroup\$ No problem, neither I got it right the first time. I suggest to delete your answer while thinking (you can undelete any time later), to avoid the chance to get downvoted. \$\endgroup\$
    – manatwork
    Commented Jun 24, 2015 at 12:18
  • \$\begingroup\$ @manatwork: I've asked the questioner for clarification, and provided an alternative answer that satisfies that reading of the rules (but it cost me 7 chars to do so) \$\endgroup\$ Commented Jun 24, 2015 at 13:03
1
\$\begingroup\$

K (ngn/k), 41 21 bytes

-20 bytes by adapting my answer here

{x@&y{y_x,1+y~:*x}/x}

Try it online!

  • y{...}/x set up a reduction seeded with y (the characters to repeat), run over the characters in x (the full string). confusingly, within the function itself, x and y are flipped. this ends up returning a boolean array with 2s in the positions containing the desired matches and 1s everywhere else
    • 1+y~:*x compare the first character to search for (*x) to the current character being iterated over (y), updating y with the result of 0 or 1. then add one to this; this represents the number of copies of the current character to end up returning. note that as soon as we have matched all the search characters, no more matches will be identified (since a character will never ~ (match) a 1 or 2)
    • x, append this result to the list of characters to search for (essentially overloading the reduction to end up returning the desired output)
    • y_ if there was a match, drop the first character (if there wasn't a match, this is a no-op). this allows us to search for the next search character in the next iteration of the reduction
  • x@& return the correct number of copies of each character
\$\endgroup\$
1
\$\begingroup\$

Vyxal s, 9 bytes

£ƛ¥h=[&Ḣd

Try it Online!

£ƛ¥h=[&Ḣd
£         # Put the first input in the register
 ƛ        # Map over the second input:
  ¥h=[    #  Is the current character equal to the first character of the register?
      &Ḣd #  If so, remove the first character of the register and double the current character
          #  (implicit) else, return the current character unchanged
          # s flag smashes this list into a string
\$\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.