34
\$\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\$ 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\$ 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\$ 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\$ Jun 24 '15 at 12:48

38 Answers 38

1
2
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\$
2
  • \$\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\$ Jun 23 '15 at 15:46
0
\$\begingroup\$

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"
\$\endgroup\$
0
\$\begingroup\$

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;
}
\$\endgroup\$
2
  • 1
    \$\begingroup\$ This 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 :( \$\endgroup\$
    – BrainSteel
    Jun 24 '15 at 16:56
  • \$\begingroup\$ @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. \$\endgroup\$ Jun 25 '15 at 8:15
0
\$\begingroup\$

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));
}
\$\endgroup\$
0
\$\begingroup\$

Perl 5 -p, 29 bytes

$_=<>=~s/./$&.$&x s!^$&!!/ger

Try it online!

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

SM83/Z80 machine language, 14 bytes

Takes input 1 in de, input 2 in hl, output to bc.

1A 13 02 03 B7 C8 BE 20
F7 02 03 23 18 F2
stretch:
 ld a,(de)                  // 1A       load input 1 char
 inc de                     // 13       and increment
 ld (bc),a                  // 02       store it
 inc bc                     // 03       and increment
 or a                       // B7       test for 0
 ret z                      // C8       return if so
 cp (hl)                    // BE       test against input 2 char
 jr nz,stretch              // 20 F7    if not same, continue
 ld (bc),a                  // 02       if same, store again
 inc bc                     // 03       and increment again
 inc hl                     // 23       also increment input 2 char
 jr stretch                 // 18 F2    loop back

The register pressure is extreme on this one. There's just enough room for three pointers and a character without pushing things to memory. It's impossible to do it this efficiently without putting the second input into hl.

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

PHP, 145 Bytes

  <?php
$a=str_split($argv[1]);
$b=str_split($argv[2]);
foreach($a as $x){
if($x==$b[0])
{
    $w[] = $x . $x;
    array_shift($b);
}
else $w[] = $x;
}
echo implode($w);

Link to compact version

Definitely not the shortest answer, but no one else has done PHP yet so why not! Takes the word as the first argument, and a string representing the characters to be duplicated for the second argument.

I'm still new to golfing, so let me know if you see anything I could improve. Thanks!

\$\endgroup\$
1
2

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.