Wrote a method that should output through recursion (using the collection iterator) all the elements of a list separated by a given character as a string. For example, there is a list that contains numbers from 1 to 5. When you call the join method, this list should be displayed in the format "1 + 2 + 3 + 4 + 5". In general, the method works, but for some reason, as a result, I get "1 + 2 + 3 + 4 + 5 +". Where am I mistaken that I have another plus after 5?

public static String join(List values, String separator) { return join(values.iterator(), separator); } public static String join(Iterator values, String separator) { if (!values.hasNext()) return ""; String firstElement = values.next() + separator; // Первый элемент списка String restElements = join(values, separator); return firstElement + restElements; } 
  • Hike the session began raining school questions =) - Serge Esmanovich

4 answers 4

Replace

 String firstElement = values.next() + separator; 

on

 String firstElement = values.next() + (values.hasNext() ? separator : ""); 

    Use the fact that if the list is not empty, you can immediately add the first element to the output, and then add to it all the others through the separator.

     public static <T> String join(Iterable<T> values, String separator) { return join(values.iterator(), separator); } public static <T> String join( Iterator<T> values, String separator) { if (!values.hasNext()) return ""; return rec( values, separator, values.next().toString() ); } private static <T> String rec( Iterator<T> values, String separator, String result ) { if ( !values.hasNext() ) return result; return rec( values, separator, result + separator + values.next() ); } public static void main(String[] args) { System.out.println( "> " + join( Arrays.asList( "Мама", "мыла", "раму" ), "+" ) ); System.out.println( "> " + join( Arrays.asList( "Тест" ), "+" ) ); System.out.println( "> " + join( Arrays.asList(), "+" ) ); } 

      You need to check one of two things:
      a) there is something to add?
      b) is there anything to add?

      Your function can be easily altered under option b)

       public static String join(Iterator values, String separator) { if (!values.hasNext()) return ""; String firstElement = values.next(); // Первый элемент списка String restElements = join(values, separator); return restElemets.isEmpty() ? firstElement : firstElement + separator + restElements; } 

      Here at each step, the tail is checked for emptiness.

      For option a) the function can be divided into two. One usual for the first element. Another recursive for the tail.

       public static String join(Iterator values, String separator) { if (values.hasNext()) return joinRest(values.next(), values, separator); else return ""; } public static String joinRest(String firstElement, Iterator values, String separator) { if (values.hasNext()) return joinRest(firstElement + separator + values.next(), values, separator); else return firstElement; } 

      No additional checks were required here. The second function ( joinRest ) will always add to what.

        Your mistake is that even the last time you add a separator to the value. And if the elements are not 5 but let's say a million, I wouldn’t really like to add a check (and not the last element). I would rather just change to:

         String finalString = firstElement + restElements; return finalString.substring(0, finalString.length() - 1); 

        Since you just need to remove the last (extra) separator.