16

I have a class Model with the following signature:

class Model {
 private String stringA;
 private String stringB;
 public Model(String stringA, String stringB) {
 this.stringA = stringA;
 this.stringB = stringB;
 }
 public String getStringA() {
 return stringA;
 }
 public String getStringB() {
 return stringB;
 }
}

I would like to map a List<Model> to a List<String> containing both stringA and stringB in a single stream

List<String> strings = models.stream()
 .mapFirst(Model::getStringA)
 .thenMap(Model::getStringB)
 .collect(Collectors.toList());

or:

List<String> strings = models.stream()
 .map(Mapping.and(Model::getStringA,Model::getStringB))
 .collect(Collectors.toList());

Of course none of them compiles, but you get the idea.

Is it somehow possible?

Edit:

Example:

Model ab = new Model("A","B");
Model cd = new Model("C","D");
List<String> stringsFromModels = {"A","B","C","D"};
Ousmane D.
56.6k8 gold badges101 silver badges134 bronze badges
asked Mar 29, 2018 at 10:31
5
  • 2
    When you say "both StringA and StringB", do you mean a concatenation? Or should your List<String> contain the StringA for your Model at index 0, then your StringB for your Model at index 0, then [...] at index 1 and so on? Commented Mar 29, 2018 at 10:34
  • 2
    A Stream generally does not like having to increase in size, that is not how it normally behaves, you can achieve what you want by using flatMap but that will be ugly. Is there any reason you don't want to use traditional for loops? Commented Mar 29, 2018 at 10:35
  • @Mena I mean the second way, so List<String> strings should contain every string from Model, both stringA and stringB. I will provide an example. Commented Mar 29, 2018 at 10:38
  • @luk2302 that is the actual solution but I was wondering if I could solve it in a stream Commented Mar 29, 2018 at 10:38
  • Then the answer is "yes, but it will neither be pretty nor better performance-wise" Commented Mar 29, 2018 at 10:39

2 Answers 2

28

You can have a list of all the values one after another like so:

List<String> resultSet =
 modelList.stream()
 .flatMap(e -> Stream.of(e.getStringA(), e.getStringB()))
 .collect(Collectors.toList());

The function passed to flatMap will be applied to each element yielding a Stream<String>. The use of flatMap is necessary here to collapse all the nested Stream<Stream<String>> to a Stream<String> and therefore enabling us to collect the elements into a List<String>.

answered Mar 29, 2018 at 10:40
2
  • @Sunflame You're welcome. I've also added some additional explanation if it helps clarify the answer :). Commented Mar 29, 2018 at 10:58
  • 1
    Thanks, now it is a lot more clear how to use flatMap, I thought it used to merge Collections or Iterables in a single stream. It really helped. Commented Mar 29, 2018 at 12:11
7

flatMap is your friend here:

models
 .stream()
 .flatMap(model -> Stream.of(model.getStringA(),model.getStringB()))
 .collect(Collectors.toList());

flatMap takes a type R and expects to give a Stream (from list,collections, Array) of new Type RR back. For each 1 model you get n new elements (in this case StringA and StringB):

{model_1[String_A1,String_B1] , model_2[String_A2,String_B2] , model_3[String_A3,String_B3]}

All your n elements { [String_A1,String_B1], [String_A2,String_B2],[String_A3,String_B3]}

are then flattened that are placed into a new Stream with structure

{String_A1,String_B1,String_A2,String_B2,String_A3,String_B3}

of Type String. That's how you have a new Stream.

You can use flatMap e.g when you have many collections/streams of elements that need to be merged into only one. For more simple explanations, check this answer

answered Mar 29, 2018 at 10:42

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.