I have a class Person having a set of Objects Contacts. I want to get a stream of Contacts from the stream of Persons.
public class Persons{
private Set<Contact> contacts;
}
persons.stream().map(Person::getContacts);
gives me Stream<Set<Contact>> rather a Stream<Contact>
Any suggestion or help would be appreciated as I am quite new to Java 8 and Streams.
You may try this:
Stream<Contact> contacts = persons.stream().flatMap(p -> p.getContacts().stream());
or that:
Stream<Contact> contacts = persons.stream().map(Person::getContacts).flatMap(Set::stream);
Check this excellent thread so that you may understand the difference between map and flatMap.
You can achieve this by using Stream#flatMap instead of Stream#map. The JavaDoc shows an example of flattening a list of lines from a file to a list of words within each line. You can adapt the same technique to your domain model of Person and Contact.
Related
return Arrays.stream(partNumbers.get())
.filter(partNumber -> Objects.nonNull(partNumber.getDescription()))
.filter(partNumber -> partNumber.getDescription().toLowerCase().contains(rateAbbr.toLowerCase()))
.findFirst();
The above code would try to find a partNumber from a list of partNumbers where partNumber's description contains a 'rateAbbr'.
This code worked till 'rateAbbr' was a String but now it is changed to a list of rateAbbrs and I need to find a part number whose description contains any of the rateAbbrs. I tried it with streams and no luck yet. any help is appreciated.
just create a private boolean function that iterates over the list and checks if there is match, then call it inside filter method.
Im traslating a old enterprise App who uses C# with Linq queries to Java 8. I have some of those queries who I'm not able to reproduce using Lambdas as I dont know how C# works with those.
For example, in this Linq:
from register in registers
group register by register.muleID into groups
select new Petition
{
Data = new PetitionData
{
UUID = groups.Key
},
Registers = groups.ToList<AuditRegister>()
}).ToList<Petition>()
I undestand this as a GroupingBy on Java 8 Lambda, but what's the "select new PetitionData" inside of the query? I don't know how to code it in Java.
I have this at this moment:
Map<String, List<AuditRegister>> groupByMuleId =
registers.stream().collect(Collectors.groupingBy(AuditRegister::getMuleID));
Thank you and regards!
The select LINQ operation is similar to the map method of Stream in Java. They both transform each element of the sequence into something else.
collect(Collectors.groupingBy(AuditRegister::getMuleID)) returns a Map<String, List<AuditRegister>> as you know. But the groups variable in the C# version is an IEnumerable<IGrouping<string, AuditRegister>>. They are quite different data structures.
What you need is the entrySet method of Map. It turns the map into a Set<Map.Entry<String, List<AuditRegister>>>. Now, this data structure is more similar to IEnumerable<IGrouping<string, AuditRegister>>. This means that you can create a stream from the return value of entry, call map, and transform each element into a Petition.
groups.Key is simply x.getKey(), groups.ToList() is simply x.getValue(). It should be easy.
I suggest you to create a separate method to pass into the map method:
// you can probably came up with a more meaningful name
public static Petition mapEntryToPetition(Map.Entry<String, List<AuditRegister>> entry) {
Petition petition = new Petition();
PetitionData data = new PetitionData();
data.setUUID(entry.getKey());
petition.setData(data);
petition.setRegisters(entry.getValue());
return petition;
}
Sorry about the title of the question; it was kind of hard for me to make sense of it. If you guys have a better title, let me know and I can change it.
I have two types of objects, Bookmark and Revision. I have one large Map, like so:
Map<Long, Bookmark> mapOfBookmarks;
it contains key: value pairs like so:
1L: Bookmark1,
2L: Bookmark2,
...
Each Bookmark has a 'getRevisions()' method that returns a Map
public Map<Long, Revision> getRevisions();
I want to create a Stream that contains all revisions that exist under mapOfBookmarks. Essentially I want to do this:
List<Revision> revisions = new ArrayList<>();
for (Bookmark bookmark : mapOfBookmarks.values()) { // loop through each bookmark in the map of bookmarks ( Map<Long, Bookmark> )
for (Revision revision : bookmark.getRevisions().values()) { // loop through each revision in the map of revisions ( Map<Long, Revision> )
revisions.add(revision); // add each revision of each map to the revisions list
}
}
return revisions.stream(); // return a stream of revisions
However, I'd like to do it using the functionality of Stream, so more like:
return mapOfBookmarks.values().stream().everythingElseThatIsNeeded();
Which would essentially be like saying:
return Stream.of(revision1, revision2, revision3, revision4, ...);
How would I write that out? Something to note is that the dataset that it is looping through can be huge, making the list method a poor approach.
I'm using Windows 7 and Java 8
A flatmap is what you looking for. When you have streams contained within a stream that you wish to flatten, then flatmap is the answer,
List<Revision> all =
mapOfBookmarks.values().stream()
.flatMap(c -> c.getRevisions().values().stream())
.collect(Collectors.toList());
You are looking for the flatMap(mapper) operation:
Returns a stream consisting of the results of replacing each element of this stream with the contents of a mapped stream produced by applying the provided mapping function to each element.
In this case, we're making a Stream<Bookmark> by calling stream(), flat mapping it to the revisions of each bookmark and, finally, collecting that into a list with toList().
List<Revision> revisions =
mapOfBookmarks.values()
.stream()
.flatMap(bookmark -> boormark.getRevisions().values().stream())
.collect(Collectors.toList());
Note that your current code could also be improved by calling addAll instead of looping over each revisions:
for (Bookmark bookmark : mapOfBookmarks.values()) { // loop through each bookmark in the map of bookmarks ( Map<Long, Bookmark> )
revisions.addAll(bookmark.getRevisions().values());
}
I am trying to implement the java based NLP „RFTagger“ to a Processing Sketch in order to analyze Tweets.
Using Twitter4j as described here http://blog.blprnt.com/blog/blprnt/updated-quick-tutorial-processing-twitter
Using RFTagger to analyze Tweets: http://sifnos.sfs.uni-tuebingen.de/resource/A4/rftj/
After I filtered out all retweets, hashtags and profile names in order to have clear sentences to work with, the words of one sentence are stored in an ArrayList:
ArrayList<String> sentsTweet = new ArrayList<String>();
Now I’d like to have the sentence analyzed by RFTagger. I just implemented the library as described on the RFTagger Website:
List <String> tags = rft.getTags(sentsTweet);
Unfortunately within Processing the class "List" is unknown / not available (?) / Error Message: Cannot find a class or type named “List“
I know I could transform the data into some other, manageable format. Like this:
Object[] tags = (rft.getTags(sentsTweet)).toArray();
But I need to store the data how it is in order to send it a second time to RFTagger to use it's tagset converter:
TagsetConverter conv = ConverterFactory.getConverter("stts");
List<String> sttsTags = new LinkedList<String>();
for ( String tag : tags ) {
sttsTags.add(conv.rftag2tag(tag));
}
Now as List<String> doesn't work in Processing do you guys have an idea how I could handle the data and or communication of RFTagger it?
Kind regards,
Marv
This has nothing to do with the processing library.
RFTagger.getTags() returns java.util.List which is part of the JDK and JRE. You need to add the import for the List class:
import java.util.List;
lets say i have 2 arrays of the objects which are mapped to each other in the following schemna:
array1 :
String [] prog_types1 = {"Program1","Program2","Program3","Program4"};
and array2 :
String [] prog_types2 ={"SubProgram1","SubProgram2","SubProgram3","SubProgram4",
"SubProgram5","SubProgram6","SubProgram7","SubProgram8","SubProgram9","SubProgram10"};
as it understood from its names, prog_types2 is an extension for prog_types1, but has some repeated values, so the full mapping between these programs would looks liek this:
prog_types1 prog_types2
ProgramType1 SubProgramType1
ProgramType1 SubProgramType2
ProgramType1 SubProgramType7
ProgramType1 SubProgramType9
ProgramType2 SubProgramType12
ProgramType2 SubProgramType7
ProgramType2 SubProgramType9
ProgramType3 SubProgramType1
ProgramType3 SubProgramType2
ProgramType3 SubProgramType21
ProgramType3 SubProgramType27
ProgramType3 SubProgramType7
ProgramType5 SubProgramType12
ProgramType5 SubProgramType9
my question is : what is the best way to map these arrays to each other, from the perspective of faster processing and reuse?
I have implemented it as :
-- set of classes (class prog1 and prog2 and after put it into vector)...
-- hashtable with hashset
-- possible one more array
the way i am looking for should not consist of creating the same prog2 objects again for prog1 object, as it would be in all of the ways described earlier, but map it by the index position for example or in any other way.
just lookin for a nice algorythmical way to resolve it...
thanks in advance
p.s. it should be used within 1 package only between couple of classes and the main use of it would be a population of the prog2 types values based on the prog1 type value
p.s.2 java7
Using MultiMap from Guava Libraries, you could say:
Multimap<String, String> mmap = ArrayListMultimap.create();
mmap.put("Program1", "SubProgramType1");
mmap.put("Program1", "SubProgramType2");
// etc.
mmap.get("Program1")
would look like:
[SubProgramType1, SubProgramType2, SubProgramType7, SubProgramType9]
BTW, Hashtable is not used now for hashed collections, has been superceded by HashMap :)
IMO the best way would be a:
Map<String, List<String>> programs = new HashMap<String, List<String>>();
with the strings in the first list as keys and the corresponding subprograms composing the value list. Now the mapping is obvious:
ProgramType1 -> [SubProgramType1, SubProgramType2, SubProgramType7, SubProgramType9]
ProgramType2 -> [SubProgramType12, SubProgramType7, SubProgramType9]
ProgramType3 -> [SubProgramType1, SubProgramType2, SubProgramType21, SubProgramType27, SubProgramType7]
ProgramType5 -> [SubProgramType12, SubProgramType9]
Guava ListMultimap, that gives List<E>, not Collection<E> - little more pleasant.
private ListMultimap<String,Something> stuff = ArrayListMultimap.create();
// ...
public void add(String key, Something item) {
stuff.put(key, item);
}
public List<Something> get(String key) {
// might as well use the Lists convenience API while we're at it.
return Lists.newArrayList(stuff.get(key));
}
http://www.coffee-bytes.com/2011/12/22/guava-multimaps
btw, since i need :
-- separately use Program1 values
-- separately use SubProgram1 values
-- populate SubProgram1 values based on Program1 value
the easiest solution here would be to declare a double dimensional array with all the dublicates (as it dysplayed in full map schema) and for 1) and 2) populate data from it using non repeating algorythm and 3) loop cycle from 2nd dimension
so no reason to declare 3 objects, huge memory save and nice approach.
i am giving myself a star for it:)