Search code examples
javaarraysloopsstringbuildercollectors

Zipped String from 2 (or more) Strings - "AB" + "YZ" = "AYBZ"


So I am trying to return another String from 2 input sentences zipped together. If the 2 sentences are identical in length it will produce an actual output. If the two input sentences are not identical in length then it will just return an empty string. Here is my code so far but I can't figure out how to zip the words correctly could someone help me. BTW it would be nice if you could help me by doing this recursively because I'm trying to practice that.

Ex:

Zippppp("ABC", "123") will return "A1B2C3"
Zippppp("AD", "CCC") will return “”
public class Zippppp
{
    public Zippppp(String a, String s)
    {
       int l1 = a.length();
       int l2 = s.length();
       if(l1 == l2)
          for(int i = 0; i > l1; i++)          
             System.out.print( a.substring(0, 1) + s.substring(0, 1));
     }
      
     public static void main(String args[ ])
     {
        Zippppp sv = new Zippppp("ABC", "123");
        System.out.print(sv);
     }
}

Solution

  • I love your class name. Sincerely

    In order to really "return" it, you could implement something similar to the examples below.

    Update/Edit: The original answer is below, as the three new approaches (which don't care about the number of strings to zip) are on top.


    [MultiThreaded]

    The ultimate ZIPPER

    Each of the words to zip is handled by a thread. Why? Ask yourself: WHY NOT???

    Boredom makes this things happen.

    Each word will be lovely processed by its own thread. Threads organize themselves in order not to process the same word and set the same positions thanks to the AtomicInteger.

    String[] mix =new String[]{"AAAZZZ","100001","BBBWWW","200002","CCCYYY","300003",
                               "DDDXXX", "400004","EEEWWW","5000005","FFFVVV","600006"};
    
    int strl = mix[0].length();        //entry's length
    int nwords = mix.length;           //number of strings
    char[] zip=new char[strl*nwords];  //the result
    
    AtomicInteger myWord = new AtomicInteger(0);
    //returning boolean if want to check some future failed(not here lol)
    List<Callable<Boolean>> callables = new ArrayList<>(nwords);  
    Callable<Boolean> zipYours =
        new Callable<Boolean>() 
        {  
            public Boolean call() 
            {  
               try
               {
                  int mine = myWord.getAndIncrement();
                  for (int x=0; x < strl; x++)
                      zip[mine+(nwords*x)]=mix[mine].charAt(x);
    
                }catch(Exception e) {
                   return false;
                }               
               
                return true;
             }  
         };
             
     for (int i=0;i<nwords;i++)
          callables.add(zipYours);
         
     //one thread - one word - true loef
     ExecutorService executor = Executors.newFixedThreadPool(nwords);
     executor.invokeAll(callables);  
     executor.shutdown();  
    
     System.out.println(new String(zip));
     /*A1B2C3D4E5F6A0B0C0D0E0F0A0B0C0D0E0F0Z0W0Y0X0W0V0Z0W0Y0X0W0V0Z1W2Y3X4W0V6*/
    

    Was this required by any means? OF COURSE NOT. But it was fun, and my girlfriend told me to do it.

    Lie, I don't have a girlfriend. Do you really think I'd be doing this if I had one??


    [Zip'em all]

    Two different approaches:

    1. Direct move

    Works regardless of the number of strings to zip, from 2 to n.* This means these approaches are also the replacement of the old methods, as you can either call getStringsZippedDirectMove("ABC,"123") or getStringsZippedDirectMove(yourArray).

    In this approach, each string is completely allocated at a time, so each element in the list is only accessed/processed once. The main loop iterates based on the number of elements in the array:

    public static String getStringsZippedDirectMove(String... mix) 
    {    
       if (!goodMix(mix))
           return "woloolooO";                //you are a blue monk now
       
       int cn = mix[0].length(), n = mix.length;   //cn = 3 | n = 6 
       char[] zip=new char[cn*n];
      
       for (int i=0; i<n; i++) 
           for (int x=0; x<cn; x++)
               zip[i+(n*x)] = mix[i].charAt(x);
          
       return  new String(zip);  
    }
    
    boolean goodMix(String ... mix)
    {
       if (mix.length<2) 
          return false;              
       for (int i=1; i<mix.length; i++)
          if (mix[i].length()!=mix[0].length())
             return false;        
       return true;
    }
    

    For example, for the first String: "AAA":

    zip[i+(n*x)]=mix[i].charAt(x); // zip[0 + (6*0)]=mix[0].charAt(0); 
    zip[i+(n*x)]=mix[i].charAt(x); // zip[0 + (6*1)]=mix[0].charAt(1);
    zip[i+(n*x)]=mix[i].charAt(x); // zip[0 + (6*2)]=mix[0].charAt(2); 
              
                zip[0]=A      zip[6]=A     zip[12]=A  
    

    For the last String: "789":

    zip[i+(n*x)]=mix[i].charAt(x); // zip[5 + (6*0)]=mix[5].charAt(0); 
    zip[i+(n*x)]=mix[i].charAt(x); // zip[5 + (6*1)]=mix[5].charAt(1);
    zip[i+(n*x)]=mix[i].charAt(x); // zip[5 + (6*2)]=mix[5].charAt(2); 
              
                zip[5]=7      zip[11]=8     zip[17]=9  
    

    enter image description here

    Same output:

     String[] mix =new String[] { "AAA","123","BBB","456","CCC","789"};
     System.out.println(getStringsZippedDirectMove(mix));   //"A1B4C7A2B5C8A3B6C9"
    

    Each iteration leads to the complete relocation of the String element's chars.

    2. Multi move from index - Holger style

    Motivated by Holger's comments

    This also will work regardless of the number of strings to zip, from 2 to n.*

    public String getStringsZippedHolger(String ... mix) 
    {    
       if (!goodMix(mix))
          return "woloolooO";           //you are a red monk now
    
       char[] zip = new char[mix[0].length()*mix.length];    
       for (int i=0, j=0; i<mix[0].length(); i++) 
          for (String s : mix)
              zip[j++] = s.charAt(i);
    
       return new String(zip);  
    }
    

    The main loop iterates three times, as it's based on each text's length (3). At each iteration, it will append the char at position i from each of the Strings in the array in the index marked by j. This last counter increments at each assignation.

    enter image description here

     String[] mix =new String[] { "AAA","123","BBB","456","CCC","789"};
     System.out.println(getStringsZippedHolger(mix));         // "A1B4C7A2B5C8A3B6C9"
    
     System.out.println(getStringsZippedHolger("HLE","OGR"));
     System.out.println(getStringsZippedHolger("IT S","SHBS"," EO "));
    


    Original answer block (2 strings)

    Arrays

    Double assignation at each iteration

    public String getZippppppppppppppppppppppppp(String a, String s)  //a -"ABC" s -"123"
    {    
       if (s.length()!=a.length())
          return "";
       char[] zip=new char[s.length()*2];      
       for (int i=0; i<s.length(); i++) 
       {
          zip[i*2] = a.charAt(i);   
          zip[(i*2)+1] = s.charAt(i);  
       }  
       return new String(zip);  /* "A1B2C3" */
    }
    

    Loop over the length of any of the Strings and insert each element in order. During the iterations, this are the assigned values:

                 i = 0              i = 1             i = 2
          --------------------------------------------------------
                zip[0] = A        zip[2] = B         zip[4] = C
                zip[1] = 1        zip[3] = 2         zip[5] = 3
      
    

    Horrendous paint:

    enter image description here

    As a result, we got:

    zip = ['A','1','B','2','C','3'] ||| new String(zip) = "A1B2C3"

    Note: If you don't love arrays, you have no hearth.

    Single assignation at each iteration

    This uses another approach for the iteration logic, which seems totally useless when you can do what the previous example does. but just for fun.

    static String getZipppppppppppppppppppppUsingCharAtThanksElliot(String a, String s)  
    {                                                                 //a -"ABC" s -"123"
      if (a.length()!=s.length()) 
          return "";
      char[] zip = new char[s.length()*2];
      int c=0;
      boolean even = false;
      for(int i =0; i < (s.length()*2); i++) 
      {
         even =!even;
         if (even) 
            zip[i] = a.charAt(c); 
         else 
         {      
            zip[i] = s.charAt(c);
            c++; 
         }   
       }
       
       return new String(zip);  //--> "A1B2C3"
    }
    

    String#subString:

    public String getZippppppppppppppppppppppppp(String a, String s)  //a -"ABC" s -"123"
    {
        if (a.length()!=s.length()) 
            return "";
        String line="";
        for(int i = 0; i < s.length(); i++)
            line += ( a.substring(i*1, (i*1)+1) + s.substring(i*1, (i*1)+1) );
    
        return line;  //--> "A1B2C3"
    }
    

    Probably the worst performant approach.


    String#charAt

    Note that charAt(), correctly pointed out on Elliot's answer, will not work with this logic; it will give you a numeric text, as result of adding their respective unicode values. It won't append the characters.

    Alternatives to work with charAt() would be using the empty string workaround, or creating a char[] as in the second boring example.

    public String getZipppppppppppppppppppppUsingCharAtThanksElliot(String a, String s)  
    {                                                                 //a -"ABC" s -"123"
        if (a.length()!=s.length()) 
            return "";
        String line="";
        for(int i = 0; i < s.length(); i++)
            line +=  a.charAt(i) + "" + s.charAt(i) ; //note the empty string
    
        return line;  //--> "A1B2C3"
    }