• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Tim Cooke
  • Campbell Ritchie
  • Ron McLeod
  • Junilu Lacar
  • Liutauras Vilda
Sheriffs:
  • Paul Clapham
  • Jeanne Boyarsky
  • Henry Wong
Saloon Keepers:
  • Tim Moores
  • Tim Holloway
  • Stephan van Hulst
  • Piet Souris
  • Carey Brown
Bartenders:
  • Jesse Duncan
  • Frits Walraven
  • Mikalai Zaikin

how to rewrite this using streams?

 
author & internet detective
Posts: 41147
848
Eclipse IDE VI Editor Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I'm trying to write code to transform this data structure. Is there a way to do it with streams/lambdas? (that isn't more complex than the existing solution)

 
Saloon Keeper
Posts: 4994
186
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Do you need a Map? You might loose many keys if the values aren't unique. What about a list of Jeannes, where Jeanne is a record with two Strings?
You might get:

But whether that is indeed easier remains to be seen.
 
Jeanne Boyarsky
author & internet detective
Posts: 41147
848
Eclipse IDE VI Editor Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
The values are guaranteed to be unique. The original map is a mapping between parent keys to their direct children. However, I need the opposite for a lookup title.

I like your idea though and could convert the list of interim objects to the Map I want. (And I could use SimpleEntry or a record).

However, I don't understand how it works (and according to my compiler it doesn't). flatMap() sees an Entry on each run not something to flatten.
 
Piet Souris
Saloon Keeper
Posts: 4994
186
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
This works for me:

with

output:
J[j=x, b=a]
J[j=y, b=a]
J[j=x, b=b]
J[j=y, b=b]

Well, what happens is that every entry is mapped to a lot of Jeannes (for each string in entry.getValue() we create a Jeanne, and thus flatMap). If you do want a Map, you can group the records with an extra line.
 
Saloon Keeper
Posts: 14011
315
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I'd use the same solution as Piet, just slightly differently:
 
Jeanne Boyarsky
author & internet detective
Posts: 41147
848
Eclipse IDE VI Editor Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Ooh. A stream/map within the flatMap. I didn't think of that. I'm going to use SimpleEntry instead of the record (because I'm not on Java 17 for this project), but idea still holds. Thanks!
 
Bartender
Posts: 2184
13
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi, everyone,
What is the difference between flatmap and map in Stream API?
How do decide which one to use?
Although there are a lot web sites about flatmap vs map, I still don't fully understand it.
I would like to hear your perspective.

Thank you in advance.
 
Jeanne Boyarsky
author & internet detective
Posts: 41147
848
Eclipse IDE VI Editor Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
It's easier to understand in Groovy. Suppose you have [[a, b], [c], []] and want [a,b,c]. Groovy's flatten() does this.

Java's flatMap is similar. It takes a stream and makes it a level less nested. But it has more ceremony than Groovy's.
 
Piet Souris
Saloon Keeper
Posts: 4994
186
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
You can also say that a flatMap maps an element to a stream of other elements. So it forms a sort of 1-to-many-relation. Suppose we want to form the pairs (1, 1), (1, 2), ..., (1, 5), (2, 2), ..., (2, 5), ... (5, 5).
We can say that if we have a, say, 3, then we want to map this 3 to the pairs (3, 3), (3, 4) and (3, 5). That can be done with:

with

Now, we do not only want to do this for the value of 3, but also for the values 1 up to 5. For each of those numbers, we map that number to the stream above. Since we map each of the elements 1, ..., 5 to a stream of P's, we need a flatMap. So we get:
 
Piet Souris
Saloon Keeper
Posts: 4994
186
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Stephan van Hulst wrote:I'd use the same solution as Piet, just slightly differently:


That is a fine generic solution, but it works only when the values are unique. We had that in Jeannes case, but that will not be true in general. So, the result should be something like:

For the OCAJP people among us: how must Stephans code be adjusted?
 
Stephan van Hulst
Saloon Keeper
Posts: 14011
315
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Himai Minh wrote:What is the difference between flatmap and map in Stream API?


The conceptual difference is easy to understand: The map() method maps every input element to exactly one output element. Any time your stream contains elements that you want to convert to more or less than exactly one output element, you need flatMap().
 
Marshal
Posts: 75874
361
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
If you take the contents of an array, list, set, etc., and enter them as individual items into something else, that is called flattening. It you have a Stream<List<Foo>> and make another Stream with map(), you will map each List to something different. If you flatten it, you will convert it to a Stream<Foo>.
Addition: Stephan said something about cardinalities: if your List<Foo>s are all empty, you will end up with an empty Stream. Otherwise its cardinality will be the same as the sum of the cardinalities of its constituent parts.
 
Master Rancher
Posts: 4225
57
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Jeanne Boyarsky wrote:I'm going to use SimpleEntry instead of the record (because I'm not on Java 17 for this project), but idea still holds. Thanks!


If you're on Java 9 at least, you may find Map.entry() is more widely recognized (or should be).  Same idea though.  While I'm not a fan of using Map.Entry for an arbitrary tuple, here it seems totally appropriate.
 
Mike Simmons
Master Rancher
Posts: 4225
57
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Piet Souris wrote:That is a fine generic solution, but it works only when the values are unique. We had that in Jeannes case, but that will not be true in general. So, the result should be something like:

For the OCAJP people among us: how must Stephans code be adjusted?


To me, a Set for the values makes more sense than a List, since the point is that they are distinct.  But it's easy to modify this depending on what is really needed.
 
Piet Souris
Saloon Keeper
Posts: 4994
186
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
You are doing the OCAJP?
 
Mike Simmons
Master Rancher
Posts: 4225
57
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
No, though I once had an opportunity to help write questions for it.  Well, the Sun equivalent.

Anyway, since no one had answered, I figured I could keep the conversation going.
 
Piet Souris
Saloon Keeper
Posts: 4994
186
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
That lock- button is right below the post reply-button. Not the first time I locked a topic.

Perhaps there are no OCAJP people anymore... but just in case there is one left and reading this topic: what if we want to keep the 'toMap' method?
 
Stephan van Hulst
Saloon Keeper
Posts: 14011
315
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
It's easy. You just slap some documentation on the method that says that the results are undefined if the input map contains duplicate values.
 
reply
    Bookmark Topic Watch Topic
  • New Topic