• 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:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Combining lists using Java 8

 
Bartender
Posts: 1971
17
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Say I have two ArrayLists:

List 1:
-------
Item 1
Item 2

List 2:
------
Coffee
Soda

What I want to do is combine these two lists LINE BY LINE so I end up with a final list that has:

Item 1 - Coffee
Item 2 - Soda


------

Have tried Stream.of with both lists and concat methods, but that isn't right.

Also tried various forEach attempts, and ".map", but can't quite get this right.

--

Would appreciate some ideas how to do this Declaratively using Java 8.

Thanks,

- mike

 
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Likes 2
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
The operation you describe is often referred to as "zipping" - Zipping two lists in Java 8
 
Marshal
Posts: 8856
637
Mac OS X VI Editor BSD Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
@OP

Don't forget to "think about"/handle the cases when the lists might be not equal in terms of their sizes.
 
Mike London
Bartender
Posts: 1971
17
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Liutauras Vilda wrote:@OP

Don't forget to "think about"/handle the cases when the lists might be not equal in terms of their sizes.



Right, thanks.

My updated code, after adding the new Guava depdenncy is:

                       Stream<String> l1 = list1.stream();
                       Stream<String> l2 = list2.stream();
                       Stream <String> lineByLineConcat =  com.google.common.collect.Streams.zip(l1, l2, (s, y) -> s + " - " + y);
                       finalList = lineByLineConcat.collect(Collectors.toList());

This works!

Thanks guys!!!

--mike
 
Liutauras Vilda
Marshal
Posts: 8856
637
Mac OS X VI Editor BSD Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I thought you'd go with your own implementation (which is fairly simple). Didn't try Guava's this method, but I trust it does the job.
 
Mike London
Bartender
Posts: 1971
17
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Liutauras Vilda wrote:I thought you'd go with your own implementation (which is fairly simple). Didn't try Guava's this method, but I trust it does the job.



I thought you would post a code example, too.

The links you gave me pointed to several libraries that did the job. I already had "working code" with two nested list for-loops, but wanted to stream-ify it if possible.

Because the declarative model does stuff for you, I find it often difficult to interpolate all the online code examples, into working code.

Thank again.

- mike
 
Liutauras Vilda
Marshal
Posts: 8856
637
Mac OS X VI Editor BSD Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Mike London wrote:The links you gave me pointed to several libraries that did the job.


Junilu Lacar was the one who gave you the link.

Mike London wrote:I already had "working code" with two nested list for-loops


Don't see the necessity of two nested loops for the example data you showed us.

Mike London wrote:I find it often difficult to interpolate all the online code examples, into working code.


That is why I think would have been useful if you were written zip function yourself, so you could understand the logic behind better.





 
Liutauras Vilda
Marshal
Posts: 8856
637
Mac OS X VI Editor BSD Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
But if you are happy with the result you got - all fine
 
Mike London
Bartender
Posts: 1971
17
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Liutauras Vilda wrote:But if you are happy with the result you got - all fine



In my original posting, I listed most of the things I tried. Streams.of concat, .forEach, various lambdas, and none of that worked.

The examples I saw online where people seemed to write their own zip implementation were long and convoluted to the point of ...what's the point of doing that?

Thanks

-- mike
 
Bartender
Posts: 5465
212
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Now that we have Streams and Lambda's, we gonna use them, no matter what! I wrote a zip version using simple pre java 8, took me just a couple of minutes. Then java 8 came, I used IntStreams, taking me an hour or so to get it up and running, got capitalized that list.get(i) might not be very efficient if list is say a LinkedList.

So I thought couple of hours ago: why not combine a Stream with good old iterators? And to prevent being capitalized on solutions that are not very generic, I devised the following solution. Indeed, surgery succes, patient died, totally unreadable, and complexity for complexitie's sake. But the fun of writing it far outweights the hour and a half of hard labour. Enjoy!

First a class that is so missing: a Pair or Tuple, I kept it as short as I could

and then the zip

So now you could write
 
Mike London
Bartender
Posts: 1971
17
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I found the code below which appears simpler, but the question I have is why does the "result.add(...)" code call the toString() method? I thought toString() got called when you tried to System.out.println(someobject).

I also never realized you could just put any placeholders you wanted (like A and B) in for generic arguments.

--------

 
Piet Souris
Bartender
Posts: 5465
212
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Mike London wrote:I found the code below which appears simpler, but the question I have is why does the "result.add(...)" code call the toString() method? I thought toString() got called when you tried to System.out.println(someobject).


Well, the 'toString' method is not being called. it1 is an iterator(A) and it2 is an iterator(B) (can't use the angled brackets here, because they have a special meaning in this editor), so the calls to 'next' result in an A and a B being delivered, and from these two a new ListZip object is formed.
It is a bit simpler than mine, but mine is a tad more general, and it also deals somehow with the situation that the lists are unequal of size, This method simply stops at that point.
 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Mike London wrote:I also never realized you could just put any placeholders you wanted (like A and B) in for generic arguments.


You can but prefer to follow the naming conventions given here: https://docs.oracle.com/javase/tutorial/java/generics/types.html

In this case, A and B are probably fine. Per convention, you might also use S and U.
 
Mike London
Bartender
Posts: 1971
17
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Piet Souris wrote:

Mike London wrote:I found the code below which appears simpler, but the question I have is why does the "result.add(...)" code call the toString() method? I thought toString() got called when you tried to System.out.println(someobject).


Well, the 'toString' method is not being called. it1 is an iterator(A) and it2 is an iterator(B) (can't use the angled brackets here, because they have a special meaning in this editor), so the calls to 'next' result in an A and a B being delivered, and from these two a new ListZip object is formed.
It is a bit simpler than mine, but mine is a tad more general, and it also deals somehow with the situation that the lists are unequal of size, This method simply stops at that point.



Maybe I misunderstand, but I can set a breakpoint on toString and it runs on the result.add()
 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Mike London wrote:Maybe I misunderstand, but I can set a breakpoint on toString and it runs on the result.add()


I think you did misunderstand. The only line that would call toString() is line 21:
 
Mike London
Bartender
Posts: 1971
17
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Junilu Lacar wrote:

Mike London wrote:Maybe I misunderstand, but I can set a breakpoint on toString and it runs on the result.add()


I think you did misunderstand. The only line that would call toString() is line 21:



That was in demo code I added, but the toString() still gets called this way (when called in a REST service):

 finalList = zipLists.zip(list1, list2).stream().map(Object::toString).collect(Collectors.toList());

Perhaps it's the Object::toString() here that's doing it?

The code was initially confusing (add hours) so I missed that part.

Thanks,

-- mike
 
Piet Souris
Bartender
Posts: 5465
212
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Indeed, and I don't think that ListZip class is simple. For instance

So, in twoLists we have that A is List and B is List. However, the zip method takes a List<A> and a List<B> as parameters. Very confusing. But take note that the generic A and B from ListZip are not the same as the generic A and B from the zip method!


Edit: my reply was a reply to Junilu's post

Edit2: indeed it is the Object::toString that causes each ListZip to be transformed into a String, and the toString is used for this.
 
Mike London
Bartender
Posts: 1971
17
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Piet Souris wrote:Indeed, and I don't think that ListZip class is simple. For instance

So, in twoLists we have that A is List and B is List. However, the zip method takes a List<A> and a List<B> as parameters. Very confusing. But take note that the generic A and B from ListZip are not the same as the generic A and B from the zip method!


Edit: my reply was a reply to Junilu's post

Edit2: indeed it is the Object::toString that causes each ListZip to be transformed into a String, and the toString is used for this.



Thanks,

So maybe the zip method needs to use different parameters to keep everything sane:

 
Piet Souris
Bartender
Posts: 5465
212
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I think so, yes. You now see immediately that the generics are independent. But why make the zip method generic? Can't you leave out the <A,B> (sorry, <S, U>) there, so that the <A, B> of the ListZip will be used?
 
Mike London
Bartender
Posts: 1971
17
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Yep that works and is less confusing.  As I mentioned, I found the code online a few hours ago and have been scratching my head (eyes bleeding) ever since...

 
Piet Souris
Bartender
Posts: 5465
212
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Yes, that really looks simple! But there are some disadvantages:

1) you're now throwing away all generics, so I suggest to make a small adjustment:


2) and you're out of luck when as happens to be a Collection, or bs a TreeSet, or if you want a List<ListZip<Point, Point>> and A happens to be a Point2D.
 
Mike London
Bartender
Posts: 1971
17
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Gotcha. Thanks!

- mike
 
Piet Souris
Bartender
Posts: 5465
212
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
You're welcome, and thank you for this nice topic!
 
Mike London
Bartender
Posts: 1971
17
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I learned a lot. Been doing Java for 15+ years, but keep learning every day since there is just SO much there.

Lambas and declarative stuff is deceptively easy (as in easy for some things, not so easy for others.).

Appreciate all the great comments and input.

I added to the code the ability for a "Cartesian" listing -- each item of list 1 with every item of list 2 as an optional method.

Thanks again.

- mike
 
Bartender
Posts: 1868
81
Android IntelliJ IDE MySQL Database Chrome Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Mooo!

Your posting was just mentioned in the July 2018 CodeRanch Journal and for that you get a cow.
 
reply
    Bookmark Topic Watch Topic
  • New Topic