Reputation: 326
I have started working with Java 8 and trying to convert some loops and old syntax in my code to lambdas and streams.
So for example, I'm trying to convert this while and for loop to stream, but I'm not getting it right:
List<String> list = new ArrayList<>();
if (!oldList.isEmpty()) {// old is a List<String>
Iterator<String> itr = oldList.iterator();
while (itr.hasNext()) {
String line = (String) itr.next();
for (Map.Entry<String, String> entry : map.entrySet()) {
if (line.startsWith(entry.getKey())) {
String newline = line.replace(entry.getKey(),entry.getValue());
list.add(newline);
}
}
}
}
I wanted to know if it's possible to convert the above example to a single stream where there is a while loop inside of a for loop.
Upvotes: 15
Views: 29149
Reputation: 425013
To answer your question, it's a 1-liner:
List<String> list = oldList.stream()
.filter(line -> map.keySet().stream().anyMatch(line::startsWith))
.map(line -> map.entrySet().stream()
.filter(entry -> line.startsWith(entry.getKey()))
.map(entry -> line.replace(entry.getKey(), entry.getValue()))
.findFirst().get())
.collect(Collectors.toList());
Upvotes: 4
Reputation: 42184
You can achieve it with a stream nested in a stream created from oldList
list. Nested stream plays role of mapping current value from oldList
with a mapper defined in map
, e.g.
public static void main(String[] args) {
final List<String> oldList = Arrays.asList("asd-qwe", "zxc", "123");
final Map<String, String> map = new HashMap<String, String>() {{
put("asd", "zcx");
put("12", "09");
put("qq", "aa");
}};
List<String> result = oldList.stream()
.map(line -> map.entrySet()
.stream()
.filter(entry -> line.startsWith(entry.getKey()))
.map(entry -> line.replace(entry.getKey(), entry.getValue()))
.collect(Collectors.toList())
)
.flatMap(Collection::stream)
.collect(Collectors.toList());
System.out.println(result);
}
Following example produces output like:
[zcx-qwe, 093]
Suggested solution can be easily parallelized if needed. Functional approach with no side effects.
Upvotes: 1
Reputation: 23171
As was stated above, using streams here doesn't really add value since it makes the code harder to read/understand. I get that you're doing it more as a learning exercise. That being said, doing something like this is a slightly more functional-style approach as it doesn't have a side effect of adding to the list from within the stream itself:
list = oldList.stream().flatMap(line->
map.entrySet().stream()
.filter(e->line.startsWith(e.getKey()))
.map(filteredEntry->line.replace(filteredEntry.getKey(),filteredEntry.getValue()))
).collect(Collectors.toList());
Upvotes: 11
Reputation: 2344
I don't see why you would want to use streams here, but it is possible.
Create some test input:
List<String> oldList = Arrays.asList("adda","bddb","cddc");
Map<String,String> map = new HashMap<>();
map.put("a", "x");
map.put("b", "y");
map.put("c", "z");
List<String> list = new ArrayList<>();
The actual code:
oldList.stream()
.forEach(line -> map.entrySet().stream()
.filter(entry -> line.startsWith(entry.getKey()))
.forEach(entry -> list.add(line.replace(entry.getKey(),entry.getValue()))));
Print the outcome:
list.forEach(System.out::println);
Which is:
xddx
yddy
zddz
Upvotes: 5