4

I have a List of String and I would like to append text in front of each String in the list. I am trying to achieve this without a for/Iterator loop like a single line of code. I can't find a solution to this.

Following I have tried with a for loop but need solution without this. Is there a solution?

   List<String> strings = new ArrayList<String>();
                strings.add("a");
                strings.add("b");
                strings.add("c");
            strings.add("d");

List<String> appendedList = new ArrayList<String>();
for (String s : strings) {
    appendedList.add("D" + s);
}

Please help. Thanks.

Charles Caldwell
  • 16,649
  • 4
  • 40
  • 47
Sara
  • 115
  • 2
  • 2
  • 6
  • 6
    Why? If there was, it would be much less readable. – tckmn Sep 26 '13 at 23:31
  • The technique you propose doesn't make seem useful for most purposes. Can you explain why you'd want to do this? Is this homework? – Jeremy Sep 26 '13 at 23:33
  • No it is not a homework but one of my colleague wants to know if this is possible at all. Something like appendedList = StringUtils.append("x", strings) – Sara Sep 26 '13 at 23:39
  • you can just pass in the list by new ArrayList(strings) but ok.. – JungJoo Sep 26 '13 at 23:56
  • You want to "append text in front of each string." If you add stuff to the front it's called *prepending*. – DaoWen Sep 27 '13 at 01:50

4 Answers4

9

If you're using Java 8, then you can use the newly added replaceAll method to do this:

strings.replaceAll(s -> "D"+s);

Here's a full working example:

import java.util.Arrays;
import java.util.List;

public class StringTest {
  public static void main(String[] args) {
    List<String> strings = Arrays.asList("a", "b", "c", "d");
    strings.replaceAll(s -> "D"+s);
    System.out.println(strings);
  }
}

You could also use the new Streams API to do this, but slightly more verbosely, making a copy of the list instead of mutating (updating) the original list:

List<String> strings = Arrays.asList("a", "b", "c", "d");
strings = strings.stream()
                 .map(s -> "D"+s) // Using Lambda notation to update the entries
                 .collect(Collectors.toList());
System.out.println(strings);

Note that I used Arrays.asList() to create the list more succinctly. This isn't a new feature in Java 8, so you should be able to use it in Java 5/6/7 as well. Here's my output:

$ java StringTest
[Da, Db, Dc, Dd]

Even if you're not using Java 8 right now, it's still good to note that these features have been added, and if you run into a similar problem in a year or two then you can use something from the new API!

DaoWen
  • 32,589
  • 6
  • 74
  • 101
  • Is this solution quicker than looping, in terms of speed of execution? – seinecle Sep 29 '13 at 15:58
  • @seinecle - I would guess that it's implemented internally with some sort of loop, but it's still going to add at least one extra function call per iteration (the lambda), so I'd guess it'd be slower. However, I'm not sure how good the Hotspot compiler is about inlining lambdas, so if this is in a critical region of the code, using this vs a loop might compile down to similar machine code. – DaoWen Sep 29 '13 at 16:44
2

Something like this perhaps

public List<String> recursiveAdd(List<String> strings, List<String> finalList, String prepender){
   if(strings == null || strings.size() == 0) return finalList;
   else{
       finalList.add(prepender + strings.remove(0));
       return recursiveAdd(strings,finalList,prepender);
   }
} 

strings = recursiveAdd(strings, new ArrayList<String>(), "D");

This is more a functional solution, the problem with the above code is that strings will be destroyed inside the class you can make a deep copy before calling the recursive operation if you want to avoid that!

Amr Gawish
  • 2,015
  • 1
  • 17
  • 29
  • This is a good CompSci answer to avoid the loop -- replace it with recursion! But you've forgotten to actually transform the data. – Thomas W Sep 26 '13 at 23:40
  • You can also achieve this in scala easily like this strings.asScala.map("D"+_).asJava You will have to import scala.collection.JavaConverters._ – Amr Gawish Sep 26 '13 at 23:58
1

First thought: LINQ :)

There seems to be a couple of LINQ alternatives for Java (see: Is there a Java equivalent for LINQ? and What is the Java equivalent for LINQ?) where you might be lucky to find something that work.

I'll provide you with a couple of examples that might work (not tested):

LambdaJ

Using the conversion feature of LambdaJ, I guess something like this should work:

List<String> res = extract(strings, on(String.class).toString() + "D");

JPropel-Light

Located at github. Based on the provided samples, something like this might work as well:

List<String> res = strings.select(append("D")).toList();
Community
  • 1
  • 1
Lasse Christiansen
  • 10,205
  • 7
  • 50
  • 79
0

You could write a 'functional style` version, using a library such as Google Guava. But this is generally regarded as less preferred/clear than just looping.

List<String> results = Lists.transform( inputs, new Function<String,String() {
    public String apply (String input) {
        return "D"+input;
    }
};

This is coded for Google Guava, but Apache also have a 'functional' style library.

Practically this usecase of tacking a common prefix on the strings, is not very good. Users aren't interested to see redundant prefixes on every item.. In the UI, the prefix should be presented once in the header.

Thomas W
  • 13,940
  • 4
  • 58
  • 76