I have: List<Map<String, String>> countries and I was able to get value which I am interested in by this:
String value = "";
for (int i = 0; i < countries.size(); i++) {
Map<String, String> map = countries.get(i);
if (map.containsValue(country)) {
value = map.get(COUNTRY_NAME);
}
}
return value;
so in general - if in map is country which I am interested in then I take value where key is COUNTRY_NAME.
How can I translate it to streams? I tried this way:
for (Map<String, String> m : countries) {
description = String.valueOf(m.entrySet()
.stream()
.filter(map -> map.getValue().equals(country))
.findFirst());
}
but first it doesn't work, second I still used for each loop.
You need to filter map if it's containsValue then transform your data using .map() then after .findFirst() use .orElse() to return default value if not found.
String value = countries.stream()
.filter(m -> m.containsValue(country))
.map(m -> m.get(COUNTRY_NAME))
.findFirst()
.orElse("");
I think you can try:
Stream.of(countries).reduce(Stream::concat)
.filter(map -> map.getValue().equals(country))
.findFirst();
That page seems to show things that can help you.
Check this:
Optional<Map<String, String>> countryOpt = countries
.stream()
.filter(c -> c.containsValue(COUNTRY_NAME))
.findAny();
if (countryOpt.isPresent()) {
value = countryOpt.get().get(COUNTRY_NAME);
}
Optional<String> countryOptional = countries.stream()
.filter(kvp -> kvp.containsKey(COUNTRY_NAME))
.map(kvp -> kvp.get(COUNTRY_NAME))
.findFirst();
Related
I am trying to search something into a map and I wanted to do that with streams but I could not figure out how to do. Could anyone help please?
The old fashioned code is like this:
String softwareIp = "1.1.1.1";
String softwareName = "Soft"
Map<String, Object> mymap; // {"1.1.1.1-12": Obj, "1.1.1.1-13":Obj, "1.1.1.2-3:Obj...etc}
Obj object = null;
for (Map.Entry entry : mymap) {
if (entry.getKey().toString().contains(softwareIP)) {
if (entry.getValue().getName().contains(softwareName)) {
object = entry.getValue();
}
}
}
The stream code I tried to write:
Obj object = mymap.entrySet().stream()
.filter(e -> (e.getKey().toString().contains(softwareIP) &&
e.getValue().contains(softwareName)))
.map(mymap::get)
.findFirst()
.orElse(null);
Where is the problem in the stream code? What should I change? I returns null.
Try this one:
Object object = mymap.entrySet().stream()
.filter(e -> e.getKey().contains(softwareIp)
&& ((REFERENCE_CLASS) e.getValue()).getName().contains(softwareName))
.findFirst()
.map(Map.Entry::getValue) //<--- if you want value
//.map(Map.Entry::getKey) //<--- if you want key
.orElse(null);
Your stream solution is correct but the comparison is wrong.
Wrong: e.getValue().contains(softwareName)
Correct: e.getValue().getName().contains(softwareName)
try this .map(n -> n.getValue())
String softwareIp = "1.1.1.1";
String softwareName = "Soft";
Map<String, String> mymap = new HashMap<>(); // {"1.1.1.1-12": Obj, "1.1.1.1-13":Obj, "1.1.1.2-3:Obj...etc}
mymap.put("1.1.1.1-12", "Soft");
String obj;
obj = mymap.entrySet().stream()
.filter(e -> (e.getKey().contains(softwareIp) &&
e.getValue().contains(softwareName)))
.map(n -> n.getValue())
.findFirst()
.orElse(null);
System.out.println(obj);
I'm trying to use Java stream to filter some values based on certain conditions. I am able to achieve the same using traditional for loops and a little bit of streams, but I want to rewrite the same logic fully in streams.
Original code:
public List <String> getProductNames(Hub hub, String requestedGroup) {
List <SupportedProduct> configuredProducts = repo.getSupportedProducts(hub);
List <String> productNames = new ArrayList <> ();
for (SupportedProduct supportedProduct: configuredProducts) {
List < String > categoryNameList = new ArrayList <> ();
String activeCategoryName = supportedProduct.getCategoryDetails().getActiveCategoryName();
if (activeCategoryName == null) {
Optional.ofNullable(supportedProduct.getCategoryDetails().getCategories())
.orElse(Collections.emptyList())
.forEach(category - > categoryNameList.add(category.getName()));
} else {
categoryNameList.add(activeCategoryName);
}
for (String catName: categoryNameList) {
Division division = divisionRepo.getDivisionByCatName(catName);
if (division != null && division.getGroup() == requestedGroup) {
productNames.add(supportedProduct.getProductName());
}
}
}
return productNames;
}
My try:
return Optional.ofNullable(configuredProducts).orElse(Collections.emptyList()).stream()
.map(supportedProduct -> {
List<String> categoryNameList = new ArrayList<>();
String activeCategoryName = supportedProduct.getCategoryDetails().getActiveCategoryName();
if (activeCategoryName == null) {
Optional.ofNullable(supportedProduct.getCategoryDetails().getCategories())
.orElse(Collections.emptyList())
.forEach(category -> categoryNameList.add(category.getName()));
} else {
categoryNameList.add(activeCategoryName);
}
return categoryNameList;
})
.filter(catName ->{
Division division = divisionRepo.getDivisionByCatName(catName);
return division != null && division.getGroup() == requestedGroup;
})........
But I'm lost beyond this.
Please help me to write the same using streams.
EDIT: Added IDEOne for testing - Link
The logic inside is quite complicated, however, try this out:
public List <String> getProductNames(Hub hub, String requestedGroup) {
List<SupportedProduct> configuredProducts = repo.getSupportedProducts(hub);
// extract pairs:
// key=SupportedProduct::getProductName
// values=List with one activeCategoryName OR names of all the categories
Map<String, List<String>> namedActiveCategoryNamesMap = configuredProducts.stream()
.collect(Collectors.toMap(
SupportedProduct::getProductName,
p -> Optional.ofNullable(p.getCategoryDetails().getActiveCategoryName())
.map(Collections::singletonList)
.orElse(Optional.ofNullable(p.getCategoryDetails().getCategories())
.stream()
.flatMap(Collection::stream)
.map(Category::getName)
.collect(Collectors.toList()))));
// look-up based on the categories' names, group equality comparison and returning a List
return namedActiveCategoryNamesMap.entrySet().stream()
.filter(entry -> entry.getValue().stream()
.map(catName -> divisionRepo.getDivisionByCatName(catName))
.filter(Objects::nonNull)
.map(Division::getGroup)
.anyMatch(requestedGroup::equals))
.map(Map.Entry::getKey)
.collect(Collectors.toList());
}
I recommend splitting into separate methods for sake of readability (the best way to go).
The verbose logics of Optional chains including two orElse calls can be surely simplified, however, it gives you the idea.
You can perform within one Stream using Collectors.collectingAndThen. In that case, I'd extract the Function finisher elsewhere, example:
public List<String> getProductNames(Hub hub, String requestedGroup) {
return repo.getSupportedProducts(hub).stream()
.collect(Collectors.collectingAndThen(
Collectors.toMap(
SupportedProduct::getProductName,
categoryNamesFunction()),
productNamesFunction(requestedGroup)));
}
private Function<Map<String, List<String>>, List<String>> productNamesFunction(String requestedGroup) {
return map -> map.entrySet().stream()
.filter(entry -> entry.getValue().stream()
.map(divisionRepo::getDivisionByCatName)
.filter(Objects::nonNull)
.map(Division::getGroup)
.anyMatch(requestedGroup::equals))
.map(Map.Entry::getKey)
.collect(Collectors.toList());
}
private Function<SupportedProduct, List<String>> categoryNamesFunction() {
return p -> Optional.ofNullable(p.getCategoryDetails().getActiveCategoryName())
.map(Collections::singletonList)
.orElse(Optional.ofNullable(p.getCategoryDetails().getCategories())
.stream()
.flatMap(Collection::stream)
.map(Category::getName)
.collect(Collectors.toList()));
}
I have the following Map structure
{empId=1234, empName=Mike, CDetails=[{"collegeName":"Peters Stanford","collegeLoc":"UK","collegeLoc":"UK"}]}
I need to read the value collegeLoc from the above Map
I tried this way , its working , but is there any better way
myMap.entrySet().stream().filter(map -> map.getKey().equals("CDetails")).forEach(e -> {
List<Object> objsList = (List<Object>) e.getValue();
for(int i=0;i<objsList.size();i++)
{
HashMap<String,String> ltr = (HashMap<String, String>) objsList.get(i);
System.out.println(ltr.get("collegeLoc"));
}
});
CDetails is a List, not a Map.
Try this:
empMap.entrySet().stream()
.map(map -> map.get("CDetails"))
.filter(Objects::nonNull)
.flatMap(List::stream)
.map(element -> ((Map)element).get("collegeLoc"))
.filter(Objects::nonNull)
.forEach(System.out::println);
How do I write below code using Java8?
for (Entry<Integer, Map<String, Object>> entry : data.entrySet()) {
Map<String, Object> value = entry.getValue();
if (value.get(Constants.USER_TRAN_ID).equals(stsTxn.getSeedTrade().getTransactionId())) {
closedTaxLotByTxnId = value;
break;
}
}
I am clueless after this
data.values().stream().map(e -> e.get(Constants.USER_TRAN_ID)).filter(txnId -> txnId.equals(stsTxn.getSeedTrade().getTransactionId()));
You don't need map. Just use filter with your criteria, and findFirst as terminal operation:
Optional<Map<String, Object>>
value = data.values()
.stream()
.filter(m -> m.get(Constants.USER_TRAN_ID).equals(stsTxn.getSeedTrade().getTransactionId()))
.findFirst();
If you want a default value (such as null) when no match is found, use:
Map<String, Object> closedTaxLotByTxnId =
data.values()
.stream()
.filter(m -> m.get(Constants.USER_TRAN_ID).equals(stsTxn.getSeedTrade().getTransactionId()))
.findFirst()
.orElse(null);
I'm searching a solution for this problem(it is for an exam):
I have a Map < String, SortedSet < String > > operators populated by a function
public void addOperator(String operatorName, String... destinationNames) throws ProposalException {
if(operators.containsKey((operatorName))){
throw new ProposalException("Operator " + operatorName + "already into system!");
}
else{
SortedSet<String> destinationstemp=new TreeSet<>();
for(String s: destinationNames){
if(s!=null){
destinationstemp.add(s);
}
}
operators.put(operatorName, destinationstemp);
}
Now, i want to create a new Map < String, SortedSet < String > > destinations that has as key the destinationName and as values the operatorNames related.
How can i make this out?
P.S: this one up there is the usage of the methods and the not-in-code part is the output wanted. Sorry for the bad formattation of the code. ph is the instance of the façade pattern class
public SortedSet<String> getDestOperators(String destinationName) {...}//method that returns the **destinations** values related to destinationName}
ph.addOperator("op3","london","rome");
ph.addOperator("op2","london","berlin");
ph.addOperator("op5","berlin","rome","madrid");
ph.addOperator("op1","london","madrid","berlin");
ph.addOperator("op10","rome");
ph.addOperator("op4","madrid","berlin");
System.out.println(ph.getDestOperators("madrid"));
Output: [op1, op4, op5]
you need to go through each entry in your map and check if inner set contains the value you are checking against,
public SortedSet<String> getDestOperators(String destinationName) {
Set<String> result = new HashSet<String>();
for(Map.Entry<String,Set<String>> entry : operators.getValues()){
if(entry.getValue().contains(destinationName)){
results.add(entry.getKey());
}
}
return result;
}
To get your example output a simple one-liner with streams:
List<String> result = operators.entrySet().stream().filter(entry -> entry.getValue().contains(destinationName)).map(Entry::getKey).sorted().collect(Collectors.toList());
or here for better readability spread over multiple lines:
List<String> result = operators
.entrySet()
.stream()
.filter(entry -> entry.getValue().contains(destinationName))
.map(Entry::getKey)
.sorted()
.collect(Collectors.toList());
A more complex one-liner if you want to "reverse" the mapping as described in your text:
Map<String, List<String>> result = operators.entrySet().stream().flatMap(entry -> entry.getValue().stream().collect(Collectors.toMap(Function.identity(), o -> Arrays.asList(entry.getKey()))).entrySet().stream()).collect(Collectors.toMap(Entry::getKey, Entry::getValue, (a, b) -> Stream.of(a, b).flatMap(List::stream).sorted().collect(Collectors.toList())));
or here for better readability spread over multiple lines:
Map<String, List<String>> result2 = operators
.entrySet()
.stream()
.flatMap(entry -> entry
.getValue()
.stream()
.collect(Collectors.toMap(Function.identity(),
o -> Arrays.asList(entry.getKey())))
.entrySet()
.stream())
.collect(Collectors.toMap(Entry::getKey,
Entry::getValue,
(a, b) -> Stream.of(a, b)
.flatMap(List::stream)
.sorted()
.collect(Collectors.toList())));
What you need to do, is loop over each operator, and then loop over all entries in the list, if value from the list is not yet present in your output map, you add it, else you modify its colection of operators.
Here is some code for you:
origin.forEach((key, list) -> {list.forEach(city -> {
if(result.containsKey(city))
result.get(city).add(key);
else{
SortedSet<String> set = new TreeSet<>();
set.add(key);
result.put(city, set);
});
});