32
\$\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\$
  • \$\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\$ – Stretch Maniac Jun 22 '15 at 16:03
  • \$\begingroup\$ Yeah sorry, reading it again that's obvious. Thanks. \$\endgroup\$ – Alex A. Jun 22 '15 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\$ – Martin Ender Jun 23 '15 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\$ – Stretch Maniac Jun 23 '15 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\$ – Toby Speight Jun 24 '15 at 12:48

33 Answers 33

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\$
43
\$\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\$
  • 22
    \$\begingroup\$ That feeling when BF is shorter than my Python code.. :( \$\endgroup\$ – Kade Jun 22 '15 at 15:24
  • 6
    \$\begingroup\$ I usually don't care for Brainfuck, but this is awesome! \$\endgroup\$ – Dennis Jun 22 '15 at 15:41
  • \$\begingroup\$ This is beautiful. \$\endgroup\$ – Joshpbarron Jun 23 '15 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\$
  • \$\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. Jun 22 '15 at 16:13
  • 3
    \$\begingroup\$ @AlexA. Just wait for Pyth. You just wait... \$\endgroup\$ – Sp3000 Jun 22 '15 at 16:18
  • 2
    \$\begingroup\$ Sounds like you'd better learn Pyth. ;) \$\endgroup\$ – Alex A. Jun 22 '15 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\$
  • 1
    \$\begingroup\$ Thanks for making me look up the comma operator. That's useful! \$\endgroup\$ – Oliphaunt Jun 23 '15 at 10:45
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\$

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\$
  • 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 Jun 22 '15 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\$ – Martin Ender Jun 22 '15 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\$ – Martin Ender Jun 23 '15 at 12:19
  • \$\begingroup\$ As an aside, I just realized that Retina doesn't have a page on esolangs.org \$\endgroup\$ – mbomb007 Jun 23 '15 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\$ – Martin Ender Jun 23 '15 at 15:44
8
\$\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\$
6
\$\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\$
  • 1
    \$\begingroup\$ I'm not really sure why this got downvoted. Maybe add some explanation to your code? \$\endgroup\$ – Alex A. Jun 22 '15 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 Jun 23 '15 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 Jun 23 '15 at 11:35
5
\$\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\$
  • \$\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 Jun 22 '15 at 19:49
  • 2
    \$\begingroup\$ You can get the first element from a possibly-empty string as y[:1]. \$\endgroup\$ – xnor Jun 22 '15 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 Jun 22 '15 at 20:42
  • \$\begingroup\$ @Vioz- I was thinking y[:1]==c. Does that work? \$\endgroup\$ – xnor Jun 22 '15 at 20:46
  • \$\begingroup\$ @xnor Yes, it does if I take the letters that need replacing instead. Thanks! \$\endgroup\$ – Kade Jun 22 '15 at 20:47
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\$
  • 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\$ – Nic Hartley Jun 23 '15 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\$ – Wightboy Jun 23 '15 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\$ – Nic Hartley Jun 23 '15 at 14:16
  • \$\begingroup\$ @QPaysTaxes I agree I liked the edit. Think I just rolledbacked one too many times. \$\endgroup\$ – Wightboy Jun 23 '15 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\$ – Nic Hartley Jun 23 '15 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\$
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\$
  • 1
    \$\begingroup\$ Does this work correctly for onomatopoeia, oao? \$\endgroup\$ – Alex A. Jun 22 '15 at 17:34
  • 1
    \$\begingroup\$ @AlexA. Outputs: "oonoomaatoopooeiaa". Ah, I understand. Will fix \$\endgroup\$ – Cereal Jun 22 '15 at 17:42
  • \$\begingroup\$ Fixed, I think. Added a lot of characters :( \$\endgroup\$ – Cereal Jun 22 '15 at 17:54
  • \$\begingroup\$ Instead of b.indexOf(d)==0, try ~b.search(d) \$\endgroup\$ – Ismael Miguel Jun 22 '15 at 17:55
  • \$\begingroup\$ @IsmaelMiguel search is only applicable on strings. Had to change b to an array \$\endgroup\$ – Cereal Jun 22 '15 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\$
  • \$\begingroup\$ @isaacg Help? There must be something shorter... \$\endgroup\$ – Jakube Jun 22 '15 at 20:40
  • \$\begingroup\$ And more elegant ;-) \$\endgroup\$ – Jakube Jun 22 '15 at 20:51
  • 1
    \$\begingroup\$ Got it in 14 - 1 less than CJam is the best place to be. \$\endgroup\$ – isaacg Jul 13 '15 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\$
2
\$\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\$
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\$
  • \$\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 Jun 24 '15 at 16:02
  • \$\begingroup\$ @manatwork That should do it. And thanks for the for hint. It's actually shorter now. \$\endgroup\$ – jja Jun 24 '15 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\$
  • \$\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 Jun 23 '15 at 19:41
2
\$\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\$
2
\$\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\$
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\$
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\$
  • \$\begingroup\$ I really like that debug switch in your interpreter. \$\endgroup\$ – Dennis Jun 22 '15 at 17:22
  • \$\begingroup\$ @Dennis Thanks! \$\endgroup\$ – kirbyfan64sos Jun 22 '15 at 17:23
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\$
  • \$\begingroup\$ You could use cat(p,sep='') to output straight to STDOUT for a couple \$\endgroup\$ – MickyT Jun 23 '15 at 0:32
  • \$\begingroup\$ @MickyT: Didn't think of that! Thanks, edited. :) \$\endgroup\$ – Alex A. Jun 23 '15 at 1:27
  • 1
    \$\begingroup\$ Actually, message(p) is shorter. \$\endgroup\$ – jja Jun 24 '15 at 11:29
  • \$\begingroup\$ @jja: I didn't know about message, that's awesome! Thanks! Edited to use your suggestion. \$\endgroup\$ – Alex A. Jun 24 '15 at 14:21
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\$
  • \$\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 Jun 24 '15 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\$ – Toby Speight Jun 24 '15 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 Jun 24 '15 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\$ – Toby Speight Jun 24 '15 at 13:03
0
\$\begingroup\$

Python, 53 92 bytes

Found my solution to be the same length in both Python 2 and 3.

EDIT: Man, fixing that case when doing multiple replaces of the same letter (while still using the same method) took a bit of work.

Python 2:

Try it here

def f(s,t):
 for c in t:s=s.replace(c,'%',1)
 print s.replace('%','%s')%tuple(x*2for x in t)

Python 3:

s,*t=input()
for c in t:s=s.replace(c,'%',1)
print(s.replace('%','%s')%tuple(x*2for x in t))
\$\endgroup\$
0
\$\begingroup\$

Mathematica, 66 bytes

""<>Fold[Most@#~Join~StringSplit[Last@#,#2->#2<>#2,2]&,{"",#},#2]&

Example:

In[1]:= f = ""<>Fold[Most@#~Join~StringSplit[Last@#,#2->#2<>#2,2]&,{"",#},#2]&

In[2]:= f["banana", {"n", "a"}]

Out[2]= "bannaana"
\$\endgroup\$
0
\$\begingroup\$

Lua, 76 78 76 75 58 53 bytes

New, completely reworked solution with help from wieselkatze and SquidDev! come on guys, we can beat brainfuck :P

function f(a,b)print((a:gsub("["..b.."]","%1%1")))end

Explanation coming tommorow. Try it here.


Original solution: Saved 2 bytes thanks to @kirbyfan64sos!

Lua is a pretty terrible language to golf in, so I think I did pretty good for this one.

function f(x,y)for i=1,#x do g=y:sub(i,i)x=x:gsub(g,g..g,1)end print(x)end

Code explanation, along with ungolfed version:

function f(x,y) --Define a function that takes the arguements x and y (x is the string to stretch, y is how to stretch it)
  for i=1,#x do --A basic for loop going up to the length of x
    g=y:sub(i,i) -- Define g as y's "i"th letter
    x=x:gsub(g,g..g,1) --Redefine x as x with all letter "g"s having an appended g after them, with a replace limit of 1.
  end
  print(x)
end

Try it here. (Outdated code but same concept, just less golfed, will update tommorow)

\$\endgroup\$
  • \$\begingroup\$ Added on two bytes because I had to fix glitch where it would replace all letter defined in the array with their duplicates. \$\endgroup\$ – user40734 Jun 22 '15 at 19:27
  • \$\begingroup\$ I think you can remove the newlines after function f(x,y) and after print(x), saving you two bytes. \$\endgroup\$ – kirbyfan64sos Jun 23 '15 at 15:46

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.