Stretching Words

32

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>

Stretch Maniac

Posted 2015-06-22T14:31:14.737

Reputation: 3 971

@AlexA. only one instance because otherwise the array formed by the duplicate letters would be [c,o,c,o], rather than [c,o]. – Stretch Maniac – 2015-06-22T16:03:22.067

Yeah sorry, reading it again that's obvious. Thanks. – Alex A. – 2015-06-22T16:08:44.880

2

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.

– Martin Ender – 2015-06-23T13:12:47.043

@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. – Stretch Maniac – 2015-06-23T20:49:52.597

@StretchManiac That's because some of the answers contain links in their headers which they shouldn't. I'll fix them. – Martin Ender – 2015-06-23T20:50:59.107

"You may also assume that the inputs have no consecutive letters which are the same (NOT apple, geek, green, glass, door...)" both inputs or just the first one? There's an example with "ooaoo" as second input and my code breaks in this case. – aragaer – 2015-06-24T11:33:39.553

1Clarification (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. – Toby Speight – 2015-06-24T12:48:54.967

Is there a maximum length on either piece of input? – Sparr – 2015-06-24T16:49:42.563

@aragaer that is only the first input, not the array, I'll clarify that. – Stretch Maniac – 2015-06-24T22:41:54.317

@TobySpeight that sentence was meant to merely state that the input possible, for example there would be no banana ,[t,x]. In your example, the duplicated letters would form [a,n], not [n,a]. I'll clarify that in the question. – Stretch Maniac – 2015-06-24T22:45:18.197

I'm still not completely sure - is banana, na => baannana allowed? Or am I only allowed bannaana, bannanaa or banannaa for that input? – Toby Speight – 2015-06-25T08:19:56.103

@TobySpeight No. That is not allowed (your first sentence). – Stretch Maniac – 2015-06-25T21:57:28.777

Answers

5

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.

isaacg

Posted 2015-06-22T14:31:14.737

Reputation: 39 268

43

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:

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

Mitch Schwartz

Posted 2015-06-22T14:31:14.737

Reputation: 4 899

22That feeling when BF is shorter than my Python code.. :( – Kade – 2015-06-22T15:24:31.793

6I usually don't care for Brainfuck, but this is awesome! – Dennis – 2015-06-22T15:41:40.713

This is beautiful. – Joshpbarron – 2015-06-23T07:45:12.707

14

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

Dennis

Posted 2015-06-22T14:31:14.737

Reputation: 196 637

It's a battle of the CJams! You and Sp both have 15 byte CJam answers, and 15 is currently the shortest. :) – Alex A. – 2015-06-22T16:13:31.673

3@AlexA. Just wait for Pyth. You just wait... – Sp3000 – 2015-06-22T16:18:31.127

2Sounds like you'd better learn Pyth. ;) – Alex A. – 2015-06-22T17:19:51.237

12

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

BrainSteel

Posted 2015-06-22T14:31:14.737

Reputation: 5 132

1

Thanks for making me look up the comma operator. That's useful!

– Oliphaunt - reinstate Monica – 2015-06-23T10:45:09.673

11

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.

Sp3000

Posted 2015-06-22T14:31:14.737

Reputation: 58 729

9

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.

Martin Ender

Posted 2015-06-22T14:31:14.737

Reputation: 184 808

2I 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." – mbomb007 – 2015-06-22T19:28:44.307

@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.) – Martin Ender – 2015-06-22T19:33:29.900

@mbomb007 FYI, I did manage to remove the marker now, but the byte count is still the same. This still looks golfable though. – Martin Ender – 2015-06-23T12:19:00.207

As an aside, I just realized that Retina doesn't have a page on https://esolangs.org

– mbomb007 – 2015-06-23T14:55:27.963

@mbomb007 Yes, I'm aware. I'll probably add one after I've implemented a few of the more important outstanding features. – Martin Ender – 2015-06-23T15:44:18.327

8

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.

xnor

Posted 2015-06-22T14:31:14.737

Reputation: 115 687

6

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)

Fatalize

Posted 2015-06-22T14:31:14.737

Reputation: 32 976

1I'm not really sure why this got downvoted. Maybe add some explanation to your code? – Alex A. – 2015-06-22T15:54:59.790

1You 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? – Oliphaunt - reinstate Monica – 2015-06-23T10:56:13.057

@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. – Fatalize – 2015-06-23T11:35:54.317

5

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.

Kade

Posted 2015-06-22T14:31:14.737

Reputation: 7 463

"You may assume that all inputs will have the letters in the array (in order)." That should save you quite a few bytes. – mbomb007 – 2015-06-22T19:49:16.410

2You can get the first element from a possibly-empty string as y[:1]. – xnor – 2015-06-22T20:37:29.613

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. – mbomb007 – 2015-06-22T20:42:04.347

@Vioz- I was thinking y[:1]==c. Does that work? – xnor – 2015-06-22T20:46:28.613

@xnor Yes, it does if I take the letters that need replacing instead. Thanks! – Kade – 2015-06-22T20:47:18.027

5

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

Wightboy

Posted 2015-06-22T14:31:14.737

Reputation: 339

2If 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. – Fund Monica's Lawsuit – 2015-06-23T14:05:32.347

@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? – Wightboy – 2015-06-23T14:16:00.627

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. – Fund Monica's Lawsuit – 2015-06-23T14:16:57.973

@QPaysTaxes I agree I liked the edit. Think I just rolledbacked one too many times. – Wightboy – 2015-06-23T14:18:47.823

I can't tell. Mobile doesn't exactly display things nicely. Ultimately, though, what matters is the code, not the formatting. – Fund Monica's Lawsuit – 2015-06-23T14:21:56.400

4

Javascript, 47 bytes

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

Taking advantage of some ES6 features.

Cereal

Posted 2015-06-22T14:31:14.737

Reputation: 299

1Does this work correctly for onomatopoeia, oao? – Alex A. – 2015-06-22T17:34:34.580

1@AlexA. Outputs: "oonoomaatoopooeiaa". Ah, I understand. Will fix – Cereal – 2015-06-22T17:42:11.267

Fixed, I think. Added a lot of characters :( – Cereal – 2015-06-22T17:54:28.453

Instead of b.indexOf(d)==0, try ~b.search(d) – Ismael Miguel – 2015-06-22T17:55:44.240

@IsmaelMiguel search is only applicable on strings. Had to change b to an array – Cereal – 2015-06-22T18:45:31.293

It would be shorter to use replace instead of converting to an array and mappning: (a,b)=>a.replace(/./g,d=>!b.indexOf(d)?d+b.splice(0,1):d). – NinjaBearMonkey – 2015-06-22T19:48:39.677

@NinjaBearMonkey That's a great idea, thanks – Cereal – 2015-06-22T20:39:34.403

@edc65 splice modifies b in place, which is why I'm using it. If I just used a zero index, it would only replace the first character. Maybe I'm misunderstanding you comment... – Cereal – 2015-06-22T20:47:53.553

4

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.

kirbyfan64sos

Posted 2015-06-22T14:31:14.737

Reputation: 8 730

4

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.

nimi

Posted 2015-06-22T14:31:14.737

Reputation: 34 639

3

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

Jakube

Posted 2015-06-22T14:31:14.737

Reputation: 21 462

@isaacg Help? There must be something shorter... – Jakube – 2015-06-22T20:40:51.497

And more elegant ;-) – Jakube – 2015-06-22T20:51:51.370

1Got it in 14 - 1 less than CJam is the best place to be. – isaacg – 2015-07-13T02:52:30.940

3

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"]

Shmiddty

Posted 2015-06-22T14:31:14.737

Reputation: 1 209

2

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}*''}

Brian Davis

Posted 2015-06-22T14:31:14.737

Reputation: 121

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

– daniero – 2015-06-23T19:41:14.723

2

><> (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! :)

Fongoid

Posted 2015-06-22T14:31:14.737

Reputation: 971

2

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

jja

Posted 2015-06-22T14:31:14.737

Reputation: 151

2

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}

jja

Posted 2015-06-22T14:31:14.737

Reputation: 151

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

– manatwork – 2015-06-24T16:02:22.230

@manatwork That should do it. And thanks for the for hint. It's actually shorter now. – jja – 2015-06-24T16:20:38.620

2

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.

Allen G

Posted 2015-06-22T14:31:14.737

Reputation: 1 825

2

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

Jarmex

Posted 2015-06-22T14:31:14.737

Reputation: 2 045

1

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.

kirbyfan64sos

Posted 2015-06-22T14:31:14.737

Reputation: 8 730

I really like that debug switch in your interpreter. – Dennis – 2015-06-22T17:22:25.960

@Dennis Thanks! – kirbyfan64sos – 2015-06-22T17:23:19.583

1

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.

Beta Decay

Posted 2015-06-22T14:31:14.737

Reputation: 21 478

1

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>

NinjaBearMonkey

Posted 2015-06-22T14:31:14.737

Reputation: 9 925

1

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!

Alex A.

Posted 2015-06-22T14:31:14.737

Reputation: 23 761

You could use cat(p,sep='') to output straight to STDOUT for a couple – MickyT – 2015-06-23T00:32:46.757

@MickyT: Didn't think of that! Thanks, edited. :) – Alex A. – 2015-06-23T01:27:49.697

1Actually, message(p) is shorter. – jja – 2015-06-24T11:29:39.367

@jja: I didn't know about message, that's awesome! Thanks! Edited to use your suggestion. – Alex A. – 2015-06-24T14:21:32.720

1

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&/"

Toby Speight

Posted 2015-06-22T14:31:14.737

Reputation: 5 058

Incorrect. strtech na <<< banana outputs “baannana”, but first an occurrence on “n” should be doubled, only after that an occurrence of “a”. – manatwork – 2015-06-24T11:04:23.457

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. – Toby Speight – 2015-06-24T11:45:01.523

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. – manatwork – 2015-06-24T12:18:00.883

@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) – Toby Speight – 2015-06-24T13:03:03.113

1

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

SirPython

Posted 2015-06-22T14:31:14.737

Reputation: 178

0

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

mbomb007

Posted 2015-06-22T14:31:14.737

Reputation: 21 944

0

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)

user40734

Posted 2015-06-22T14:31:14.737

Reputation:

Added on two bytes because I had to fix glitch where it would replace all letter defined in the array with their duplicates. – None – 2015-06-22T19:27:09.810

I think you can remove the newlines after function f(x,y) and after print(x), saving you two bytes. – kirbyfan64sos – 2015-06-23T15:46:28.690

0

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"

alephalpha

Posted 2015-06-22T14:31:14.737

Reputation: 23 988

0

Ruby, 46 bytes

f=->s,a{a.map{|c|y,s=s.split(c,2);y+c*2}*''+s}

For each character c in the array a, divide the string s in two halves on the first occurrence of c. Add two copies of the c to the first half, and continue with the other half of s. Join it all together and add the remainder of s :)

Examples:

f["coconut", %w(c o)]
=> "ccooconut"
f["banana", %w(b a a)]
=> "bbaanaana"

daniero

Posted 2015-06-22T14:31:14.737

Reputation: 17 193

0

C, 57

Inspired by BrainSteel's answer:

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

This uses the result of putchar to determine whether we've hit one of the replacement list, and if so, advance one through the replacement list, outputting as we go.

If we don't consume all the replacements, we'll go off the end of the input string, but luckily the rules guarantee we wont. :-)

Test harness:

int main(int argc, char* argv[]) {
    f(argv[1], argv[2]);
    return 0;
}

Toby Speight

Posted 2015-06-22T14:31:14.737

Reputation: 5 058

1This code assumes no double letters in the replacement list. I don't think that's an assumption you are allowed to make, as the 4th test case has double letters. That is what drove me away from this approach :( – BrainSteel – 2015-06-24T16:56:37.487

@BrainSteel - I've withdrawn the answer that makes the assumption "no double letters in the replacement list", and edited this to a new answer. I can no longer avoid 2xputchar, but I save a few chars by using their results. – Toby Speight – 2015-06-25T08:15:58.717

0

C#, 116 bytes

Indented for clarity:

string F(string s,string c){
    int i;
    return c==""
        ?s
        :s.Remove(i=s.IndexOf(c[0]))+c[0]+F(s.Substring(i),c.Substring(1));
}

Hand-E-Food

Posted 2015-06-22T14:31:14.737

Reputation: 7 912