# String Concatenation

The Challenge

Given two strings containing only lowercase letters and no spaces, the result should be the shorter string, followed by an underscore, followed by the longer string with the first instance of a character removed for each character it contains that is in the shorter string.

You can assume the strings will always be different lengths.

Test Cases:

sale
salinewater
Result: sale_inwater (only the first 'a' in salinewater is removed)

jostling
juggle
Result: juggle_ostin (juggle is the shorter string)

juggle
juggler
Result: juggle_r (a 'g' is removed for every 'g' in the shorter string)


Rules

This is code-golf, so shortest answer in bytes wins!

• What does "remove the first occurrence" mean when the shorter string has duplicate characters? – Peter Taylor Sep 21 '16 at 7:21
• Four days is very short to pick a winner, I'd suggest at least a couple of week at minimum. Also, in the future I'd suggest first posting to the Sandbox where challenges can be clarified and improved before going live. – xnor Sep 21 '16 at 7:21
• smaller string is shorter string......sorry for my bad english – Ajay Sep 21 '16 at 7:30
• What should the output for juggle juggler be? juggle_r (remove for each character instance) or juggle_gr (remove for each distinct character)? – PurkkaKoodari Sep 21 '16 at 8:06
• @Pietu1998 That's a good point. We should put this on hold until clarified – Luis Mendo Sep 21 '16 at 8:09

# Pyth, 13 bytes

++hAlDQ\_.-HG


Try it online.

## JavaScript (ES6), 7875 69 Bytes

const
g=(x,y)=>x[y.length]?g(y,x):[...x].map(c=>y=y.replace(c,''))&&x+'_'+y
;

console.log(g.toString().length + 2);   // 69
console.log(g('sale', 'salinewater'))   // sale_inwater
console.log(g('juggle', 'juggler'))     // juggle_r
console.log(g('jostling','juggle'))     // juggle_ostin

### Breakdown

x[y.length]?g(y,x):        \\ Make sure that x is the shorter string
[...x]                     \\ Spread string in array of characters
.map(c=>y=y.replace(c,'')) \\ For each character remove its first occurence in y
&&x+'_'+y                  \\ Concat x and changed y


import Data.List
x%y|(0<$y)<(0<$x)=y%x|z<-y\\x=x++'_':z


-1 byte thanks to @xnor

• You can cut a byte by binding y\\x for the 0<1 otherwise guard. – xnor Sep 23 '16 at 9:10
• filter(notElemx)y is shorter than y\\x with import – Damien Sep 23 '16 at 16:10
• @Damien I think that would remove all occurrences of elements of x, not just the first ones. – dianne Sep 23 '16 at 16:23
• Oh, yes you are right. – Damien Sep 23 '16 at 16:26

# Java 7, 262 bytes

import java.util.*;String c(String z,String y){int i=0,l=y.length();if(z.length()>l)return c(y,z);List x=new ArrayList();for(;i<l;x.add(y.toCharArray()[i++]));for(Object q:z.toCharArray())x.remove(q);String r="";for(i=0;i<x.size();r+=x.get(i++));return z+"_"+r;}


Can probably be golfed some more by just using arrays without the lists..

Ungolfed & test cases:

Try it here.

import java.util.*;
class M{
static String c(String z, String y){
int i = 0,
l = y.length();
if(z.length() > l){
return c(y, z);
}
List x = new ArrayList();
for(Object q : z.toCharArray()){
x.remove(q);
}
String r = "";
for(i = 0; i < (x.size()); r += x.get(i++));
return z+"_"+r;
}

public static void main(String[] a){
System.out.println(c("sale", "salinewater"));
System.out.println(c("jostling", "juggle"));
System.out.println(c("juggle", "juggler"));
}
}


Output:

sale_inwater
juggle_ostin
juggle_r


# Java 8, 156 Bytes

String a(String x,String y){int l=x.length(),m=y.length();String b=l>m?x:y,s=m<l?y:x;for(char c:s.toCharArray()){b=b.replaceFirst(""+c,"");}return s+"_"+b;}


This can probably be golfed some more.

Ungolfed & test cases

interface A {
static String a(String x,String y){
int l=x.length(),m=y.length();
String b=l>m?x:y,s=m<l?y:x;
for(char c:s.toCharArray()){
b=b.replaceFirst(""+c,"");
}
return s+"_"+b;
}

static void main(String[]a) {
System.out.println(a("sale","salinewater"));
System.out.println(a("jostling","juggle"));
System.out.println(a("juggle","juggler"));
}
}


## Ruby, 65 bytes

->a,b{a,b=b,a if a.size>b.size;a.chars.map{|e|b.sub!e,""};a+?_+b}


### ungolfed

->a, b{
a, b = b, a if a.size > b.size
a.chars.map { |e|
b.sub! e, ""
}
a + ?_ + b
}


### 61 bytes(in case the argument is an array of strings)

->a{a.sort_by!(&:size);a[0].chars.map{|c|a[1].sub!c,""};a*?_‌​}


Thank you, m-chrzan!

• gsub! doesn't work here - you're supposed to remove the first occurance of each letter. Fortunately, sub!, which does exactly that, is a byte shorter. – m-chrzan Sep 23 '16 at 14:23
• Also, I think you need to name the lambda in this case, since you do end up calling it. However, doing a,b=b,a if a.size>b.size to exchange the strings is non-recursive, and saves you another byte. – m-chrzan Sep 23 '16 at 14:39
• @m-chrzan Oh, I didn't observe carefully the question. Thanks! – cia_rana Sep 23 '16 at 15:00
• 61 bytes, input as an array of strings: ->a{a.sort_by!(&:size);a[0].chars.map{|c|a[1].sub!c,""};a*?_} – m-chrzan Sep 23 '16 at 15:01

# PHP, 154 Bytes

list($f,$s)=strlen($b=$argv[2])<strlen($a=$argv[1])?[$b,$a]:[$a,$b];foreach(str_split($f)as$x)$s=preg_replace("#(.*?)".$x."(.*)#","$1$2",$s);echo$f."_$s";  Instead of $s=preg_replace("#(.*?)".$x."(.*)#","$1$2",$s); you can also use if($z=strstr($s,$x))$s=strstr($s,$x,1).substr(\$z,1);

## R, 161 bytes

This turned out to be much longer than I expected, albeit, string manipulation is usually tedious in R. I feel that this should easily be golfable by just using another approach.

function(x,y){s=strsplit;if(nchar(x)>nchar(y)){v=y;w=x}else{v=x;w=y};v=s(v,"")[[1]];w=s(w,"")[[1]];j=0;for(i in v){j=j+1;if(i==w[j])w[j]=""};cat(v,"_",w,sep="")}


### Ungofled

function(x,y){
s=strsplit                      # alias for stringsplit
if(nchar(x)>nchar(y)){v=y;w=x}  # assign v/w for the short/long strings
else{v=x;w=y}
v=s(v,"")[[1]]                  # split short string into vector
w=s(w,"")[[1]]                  # split long string into vector
j=0
for(i in v){                    # for each char in short string, check
j=j+1                       # if is equal to corresponding char in
if(i==w[j])w[j]=""          # long, replace long with "" if true
}
cat(v,"_",w,sep="")             # insert _ and print
}


# Python 2, 81 72 bytes

a,b=sorted(input(),key=len)
for c in a:b=b.replace(c,"",1)
print a+"_"+b


Try it online

• I think you can save 9 bytes by replacing the first two lines with a,b=sorted(input(),key=len) – dianne Sep 23 '16 at 8:07

# Scala, 78 bytes

def f(a:String,b:String):String={if(a.size>b.size)f(b,a)else
a+"_"+(b diff a)}


Explanation:

def f(a:String,b:String):String={ //define a method f which has two String parameters and returns a String
//(because it's recursive, scala can't figure out the return type)
if (a.size > b.size)            //make sure that a is the shorter string
f(b, a)
else
a+"_"+(b diff a)              //b diff a removes all elements/chars of a from b
}