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"};
2 Answers 2
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>
.
-
@Sunflame You're welcome. I've also added some additional explanation if it helps clarify the answer :).Ousmane D.– Ousmane D.2018年03月29日 10:58:55 +00:00Commented Mar 29, 2018 at 10:58
-
1Thanks, now it is a lot more clear how to use
flatMap
, I thought it used to mergeCollection
s orIterable
s in a single stream. It really helped.Sunflame– Sunflame2018年03月29日 12:11:02 +00:00Commented Mar 29, 2018 at 12:11
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
List<String>
contain theStringA
for yourModel
at index0
, then yourStringB
for yourModel
at index0
, then [...] at index1
and so on?flatMap
but that will be ugly. Is there any reason you don't want to use traditionalfor
loops?List<String> strings
should contain every string from Model, both stringA and stringB. I will provide an example.