• 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 all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Liutauras Vilda
  • Tim Cooke
  • Jeanne Boyarsky
  • Bear Bibeault
Sheriffs:
  • Knute Snortum
  • paul wheaton
  • Devaka Cooray
Saloon Keepers:
  • Tim Moores
  • Stephan van Hulst
  • Ron McLeod
  • Piet Souris
  • Ganesh Patekar
Bartenders:
  • Tim Holloway
  • Carey Brown
  • salvin francis

Splitting a string and then to Hashmap using Java 8 Streams

 
Ranch Hand
Posts: 99
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I have a data file where each line in the file is in this format: Gain:2:Loss:5:Processed:1:Sent:0:

I am trying to split each line of the file by the : delimiter and then copying it to a Hashmap where key is the activity and value is the number. Eg: Gain>key, 2>value. The Hashmap is used to easily access the extracted data.

I am using the new Java 8 Streams method to read files, but am stuck at copying to a Hashmap. Guidance is appreciated

 
Marshal
Posts: 65365
248
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Please explain more. Are all the lines in the form “Gain:3:Loss:4:Processed:2:Sent:1:”?
Are you using “Gain” as the “K”? In which case you might overwrite the “V”s and your Map might only contain a mapping for the last line.
Don't declare Streams if you can possibly help it. Once you have used a Stream, it is not possible to go back to it, so it is very unusual to write Stream<XYZ> stream = ...;
What you have in line 13 might be a Stream<String> but in line 14 you are turning it into a Stream<String[]>, so the type will be wrong and line 13 won't compile. You will have to declare it as type Map<...>

Use an IDE to write your code; if you hover your mouse over the method names, you will see a popup telling you the exact return type of each method. Not Stream<T> or anything vague, but Stream<String[]>.
Let's see what you have: In line 13 you are creating a Stream<String[]>, but you have some duplicated code. Don't write Paths.get(...) because you have already executed the selfsame code in line 9. Write filePath.
Line 14 changes the Steam to a Stream<String[]> by correct use of the split() method. If you look here (Java™ Tutorials), you will find that “:” isn't a metacharacter.
You were right to start line 16 with .collect(), but that needs an argument. It is usual to pass a Collector reference; the easiest way to get such a reference being this. Note that will give you a Map<K, List<V>>. I don't know whether that is going to help in you current situation, but at least it will include every line.

Adding discussion to our Streams forrum.
 
WeiJie Lim
Ranch Hand
Posts: 99
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Campbell Ritchie wrote:Please explain more. Are all the lines in the form “Gain:3:Loss:4:Processed:2:Sent:1:”?
Are you using “Gain” as the “K”? In which case you might overwrite the “V”s and your Map might only contain a mapping for the last line.
Don't declare Streams if you can possibly help it. Once you have used a Stream, it is not possible to go back to it, so it is very unusual to write Stream<XYZ> stream = ...;
What you have in line 13 might be a Stream<String> but in line 14 you are turning it into a Stream<String[]>, so the type will be wrong and line 13 won't compile. You will have to declare it as type Map<...>

Use an IDE to write your code; if you hover your mouse over the method names, you will see a popup telling you the exact return type of each method. Not Stream<T> or anything vague, but Stream<String[]>.
Let's see what you have: In line 13 you are creating a Stream<String[]>, but you have some duplicated code. Don't write Paths.get(...) because you have already executed the selfsame code in line 9. Write filePath.
Line 14 changes the Steam to a Stream<String[]> by correct use of the split() method. If you look here (Java™ Tutorials), you will find that “:” isn't a metacharacter.
You were right to start line 16 with .collect(), but that needs an argument. It is usual to pass a Collector reference; the easiest way to get such a reference being this. Note that will give you a Map<K, List<V>>. I don't know whether that is going to help in you current situation, but at least it will include every line.

Adding discussion to our Streams forrum.



Oh yes, all lines are in the same format, the only difference is in the numerical values.
Gain:3:Loss:4:Processed:2:Sent:1:
Gain:1:Loss:6:Processed:0:Sent:8:
...
Oh thanks for pointing out, in that case, Hashmap is not the right Collection to use, my bad. There doesn't seem to be a Collection that can store non-unique key value pairs. Do I have to create a 2D array for this ?
I will try to modify the code to not declare the Stream<String>, thanks
 
Campbell Ritchie
Marshal
Posts: 65365
248
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You can probably find a data structure for what you want, but please start by explaining exactly what you want your records to look like.
Don't try arrays, though.
 
WeiJie Lim
Ranch Hand
Posts: 99
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Campbell Ritchie wrote:You can probably find a data structure for what you want, but please start by explaining exactly what you want your records to look like.
Don't try arrays, though.



The end result I am trying to achieve is to be able to sum up all numerical values for each activity, and then print it.
Eg based on the 2 lines:
Gain:3:Loss:4:Processed:2:Sent:1:
Gain:1:Loss:6:Processed:0:Sent:8:

I would want to obtain Gain = 4, Loss = 10 and so on.

I stumbled upon the Pair class, but I am not sure if it is can work..

Edit:
Apologies, I only have to extract details from the first line, so a Hashmap should be fine.
 
Bartender
Posts: 6115
58
Eclipse IDE Firefox Browser MySQL Database VI Editor Java Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Campbell Ritchie wrote:You were right to start line 16 with .collect(), but that needs an argument. It is usual to pass a Collector reference; the easiest way to get such a reference being this. Note that will give you a Map<K, List<V>>. I don't know whether that is going to help in you current situation, but at least it will include every line.

As Campbell said, you can get a Map<String,List<Integer>) from the stream. This would work for you PROVIDING all your lines have exactly the same keys. Then the list is accessible by map.get( "Gain" ).get( lineNumber ). IF you have different keys you could use List<Map<String,Integer>>.
 
Campbell Ritchie
Marshal
Posts: 65365
248
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The good news is, it is very easy to pick up the individual numbers out of the array (map() method) and convert them to ints, or more precisely to convert the Stream to an IntStream (mapToInt() method). The bad news is, you would have to run the stream four times.
The good news is, you can use the forEach() method to do  the addition. The bad news is, you can't write += for a local variable. Create a Counter/Summator/Adder class and use an instance of that to do the additions.
There are bound to be better ways to do that; maybe somebody will appear in a few minutes and tell you about a far better way to do your additions.
 
Saloon Keeper
Posts: 3443
149
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Well, I don't know if this is a handy method, but it creates a List<List<Activity>>, as one of Carey's suggestions. Activity is a class that extends the javafx Pair<String, Integer>. Try also a List<Map<String, Integer>>



Edit: forgot to mention, but the 3-parameter  version of IntStream.iterate needs java 10 (or 9?)
 
WeiJie Lim
Ranch Hand
Posts: 99
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks a lot for all the help so far, I have clarified and the correct data file is in the format
Gain:3:Loss:4:Processed:2:Sent:1:
Returned:30:Total:9:

My apologies.

The following code can work, but only on 1 key:value pair per line.



Is it simpler to do it the non-Java 8 way by using regex and string manipulation instead ? I got to admit lambdas and Streams are confusing for me.
 
Piet Souris
Saloon Keeper
Posts: 3443
149
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
If every line starts with "Gain:" then this will not work, since every key of your Map would be the same. What about the already suggested Map<String, List<Integer>>? That would work, but there would be only one key ("Gain") so you might just as well make a List<Integer>.

But why do you insist on creating a Map? What's wrong with creating a class "Activity" and make a List of these?
 
WeiJie Lim
Ranch Hand
Posts: 99
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Piet Souris wrote:If every line starts with "Gain:" then this will not work, since every key of your Map would be the same. What about the already suggested Map<String, List<Integer>>? That would work, but there would be only one key ("Gain") so you might just as well make a List<Integer>.

But why do you insist on creating a Map? What's wrong with creating a class "Activity" and make a List of these?



As mentioned in my previous post, I have confirmed that it is only the first line which starts with Gain, the rest of the lines starts differently. Each activity is unique. 1 line has a max of 4 activities.
I apologize for the change in format for the data file.
 
Piet Souris
Saloon Keeper
Posts: 3443
149
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
My fault, I misunderstood your remark in that reply.

Yes, your code will work, except there is an error in line 14. forEach is a void method, so it returns nothing. Therefore, leave out the 'eachLine = '.
 
It's a pleasure to see superheros taking such an interest in science. And this tiny ad:
create, convert, edit or print DOC and DOCX in Java
https://products.aspose.com/words/java
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!