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:

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

Result: juggle_ostin (juggle is the shorter string)

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


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

  • 2
    \$\begingroup\$ What does "remove the first occurrence" mean when the shorter string has duplicate characters? \$\endgroup\$ – Peter Taylor Sep 21 '16 at 7:21
  • 2
    \$\begingroup\$ 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. \$\endgroup\$ – xnor Sep 21 '16 at 7:21
  • 3
    \$\begingroup\$ smaller string is shorter string......sorry for my bad english \$\endgroup\$ – Ajay Sep 21 '16 at 7:30
  • 6
    \$\begingroup\$ What should the output for juggle juggler be? juggle_r (remove for each character instance) or juggle_gr (remove for each distinct character)? \$\endgroup\$ – PurkkaKoodari Sep 21 '16 at 8:06
  • 2
    \$\begingroup\$ @Pietu1998 That's a good point. We should put this on hold until clarified \$\endgroup\$ – Luis Mendo Sep 21 '16 at 8:09

10 Answers 10


Pyth, 13 bytes


Try it online.


JavaScript (ES6), 78 75 69 Bytes


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


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 

Haskell, 56 55 bytes

import Data.List

-1 byte thanks to @xnor

  • \$\begingroup\$ You can cut a byte by binding y\\x for the 0<1 otherwise guard. \$\endgroup\$ – xnor Sep 23 '16 at 9:10
  • \$\begingroup\$ filter(`notElem`x)y is shorter than y\\x with import \$\endgroup\$ – Damien Sep 23 '16 at 16:10
  • \$\begingroup\$ @Damien I think that would remove all occurrences of elements of x, not just the first ones. \$\endgroup\$ – dianne Sep 23 '16 at 16:23
  • \$\begingroup\$ Oh, yes you are right. \$\endgroup\$ – 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(; i < l; x.add(y.toCharArray()[i++]));
    for(Object q : z.toCharArray()){
    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"));



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()){
        return s+"_"+b;
    static void main(String[]a) {

Ruby, 65 bytes

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


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


Thank you, m-chrzan!

  • 1
    \$\begingroup\$ 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. \$\endgroup\$ – m-chrzan Sep 23 '16 at 14:23
  • 1
    \$\begingroup\$ 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. \$\endgroup\$ – m-chrzan Sep 23 '16 at 14:39
  • \$\begingroup\$ @m-chrzan Oh, I didn't observe carefully the question. Thanks! \$\endgroup\$ – cia_rana Sep 23 '16 at 15:00
  • \$\begingroup\$ 61 bytes, input as an array of strings: ->a{a.sort_by!(&:size);a[0].chars.map{|c|a[1].sub!c,""};a*?_} \$\endgroup\$ – m-chrzan Sep 23 '16 at 15:01
  • \$\begingroup\$ @m-chrzan Great! I added your answer. \$\endgroup\$ – cia_rana Sep 23 '16 at 15:14

PHP, 154 Bytes


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


    s=strsplit                      # alias for stringsplit
    if(nchar(x)>nchar(y)){v=y;w=x}  # assign v/w for the short/long strings
    v=s(v,"")[[1]]                  # split short string into vector
    w=s(w,"")[[1]]                  # split long string into vector
    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

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

Try it online

  • 2
    \$\begingroup\$ I think you can save 9 bytes by replacing the first two lines with a,b=sorted(input(),key=len) \$\endgroup\$ – 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)}


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)
    a+"_"+(b diff a)              //`b diff a` removes all elements/chars of a from b

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.