Collect HashMap<String,Object> from Stream<T> - java

Using Map of key to iterate and based on condition returning HashMap,need to collect return map below code.
trying to convert below java code in java 8
for (String key : sectionsJson.keySet()) {
Map<String, Object> section = (Map<String, Object>) sectionsJson.get(key);
if (index == (Integer) section.get(SECTION_FIELD_KEY_INDEX)) {
section.put(SECTION_FIELD_KEY_SECTION_KEY, key);
return section;
}
}
any suggestion.

It looks like you want to produce a Map having at most a single entry.
Map<String,Object> map =
sectionsJson.entrySet()
.stream()
.filter(e -> {
Map<String, Object> section = e.getValue ();
return index == (Integer) section.get(SECTION_FIELD_KEY_INDEX);
}
.map(e -> new SimpleEntry<> (SECTION_FIELD_KEY_SECTION_KEY, e.getKey ()))
.limit(1)
.collect(Collectors.toMap(Map.Entry::getKey,Map.Entry::getValue));
It looks like your original code is simpler.
Perhaps you can simply search for the desired key:
String value =
sectionsJson.entrySet()
.stream()
.filter(e -> {
Map<String, Object> section = e.getValue ();
return index == (Integer) section.get(SECTION_FIELD_KEY_INDEX);
}
.map(Map.Entry::getKey)
.findFirst()
.orElse(null);
since you are producing a Map having (at most) a single value and a constant key, so the value is the only data the Stream pipeline should be searching for.

As per your existing code. You are returning the map as soon as it finds any match. Same thing you can do using java 8 as well.
Optional<Integer> findAny = sectionsJson.keySet().stream().filter(key -> {
Map<String, Object> section = (Map<String, Object>)sectionsJson.get(key);
if (index == (Integer)section.get("SECTION_FIELD_KEY_INDEX")) {
section.put("SECTION_FIELD_KEY_SECTION_KEY", key);
return true;
}
return false;
}).findFirst();
if (findAny.isPresent()) {
System.out.println(sectionsJson.get(findAny.get()));
}

Depending on what you want to achieve following might be also possible solutions:
simplifying the loop
for (Map.Entry<String, Map<String, Object>> entry : sectionsJson.entrySet()) {
Map<String, Object> section = entry.getValue();
if (index == section.get(SECTION_FIELD_KEY_INDEX)) {
section.put(SECTION_FIELD_KEY_SECTION_KEY, entry.getKey());
return section;
}
}
// add the code for the case when no section was found
separate stream processing and mutating the element
// find the section
Optional<Map.Entry<String, Map<String, Object>>> first = sectionsJson.entrySet().stream()
.filter(e -> (Integer) e.getValue().get(SECTION_FIELD_KEY_INDEX) == index)
.findFirst();
// mutate the section
if (first.isPresent()) {
Map.Entry<String, Map<String, Object>> sectionJson = first.get();
sectionJson.getValue().put(SECTION_FIELD_KEY_SECTION_KEY, sectionJson.getKey());
return sectionJson.getValue();
}
// add the code for the case when no section was found

Related

How to filter a HashMap with a value Predicate?

I have the following query header method:
public Map<String, List<String>> query(Predicate<String> valuePredicate)
Before this, I implementated another method with a specific column (label). It was:
public Map<String, List<String>> query(String keySelector,Predicate<String> valuePredicate) {
try {
final List<String> row = frameInfo.get(keySelector);
List<Integer> indices = IntStream.range(0, row.size()).filter(columnIndex -> valuePredicate.test(row.get(columnIndex))).boxed().collect(Collectors.toList());
Map<String, List<String>> auxMap = new HashMap<>();
for (Map.Entry<String, List<String>> entry : frameInfo.entrySet()) {
for (int columnIndex : indices) {
auxMap.putIfAbsent(entry.getKey(), new ArrayList<>());
auxMap.get(entry.getKey()).add(entry.getValue().get(columnIndex));
}
}
return auxMap;
}catch (Exception e){
return null;
}
How could I implementate the new method with just 1 argument (valuePredicate)?
It seems to me that you could do it like so. Since the predicate tests a string from a list which can be streamed, I don't see why you need to iterate the indices.
Stream the entrySet from frameInfo
then flatmap e.getValue() (a list) and apply the predicate
preserve the key and filtered value in a String array
then group based on the key
public Map<String, List<String>> queryAll(Predicate<String> valuePredicate) {
return frameInfo.entrySet().stream()
.flatMap(e -> e.getValue().stream()
.filter(valuePredicate)
.map(s -> new String[] { e.getKey(), s }))
.collect(Collectors.groupingBy(arr -> arr[0],
Collectors.mapping(arr -> arr[1],
Collectors.toList())));
}
I'm tossing this one in as well, it's a rewrite of your existing method.
it simply streams the list for the supplied key, applies the filter and populates the map. Since there is only one key, you could just return a list.
public Map<String, List<String>> query(String keySelector,
Predicate<String> valuePredicate) {
return frameInfo.get(keySelector).stream()
.filter(valuePredicate)
.collect(Collectors.groupingBy(a -> keySelector));
}
If I misunderstood something, let me know and I will try to correct it.

Get String from List of Maps in Java 8

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();

map of map get outer map based on inner map value

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);

Test for true against boolean or notnull / empty against string

In order to get the names of the Sections with True or NotNull/NotEmpty values I am creating a Map from the following Java object then iterating over it.
public class Assessment {
private Boolean section1Checkbox1;
private Boolean section1Checkbox2;
private Boolean section1Comments;
private Boolean section2Checkbox1;
private Boolean section2Checkbox2;
private Boolean section2Comments;
more sections.....
I have converted the object to a Map which I then iterate over:
Map<String, Object> map = oMapper.convertValue(needsAssessment, Map.class);
Iterator it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry)it.next();
if (pair.getValue()==true||NotNull) {
// Get Section Name
String[] sectionName = pair.getKey().toString().split("(?=\\p{Upper})");
System.out.println(sectionName[0]);
}
}
There is a error with the pair.getValue() test:
Is there a way to test for true (if boolean) and NotNull or Empty (if
string) in one statement?
(Or a better approach?)
This code works thanks #Lino :
Map<String, Object> map = oMapper.convertValue(assessment, Map.class);
System.out.println(map);
Iterator it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry)it.next();
if (pair.getValue() instanceof Boolean) {
Boolean currentCheckbox = (Boolean) pair.getValue();
// Get Section/Subject Name
System.out.println(pair.getKey());
if (currentCheckbox) {
String[] sectionName = pair.getKey().toString().split("(?=\\p{Upper})");
System.out.println(sectionName[0]);
}
}
}
Here's some code, which shows the more idiomatic Java 8+ way of using lambdas and streams for collection filtering and transforming:
Map<String, Object> map = oMapper.convertValue(assessment, Map.class);
map.entrySet()
// stream all entries
.stream()
// filter by value being TRUE (this is null safe)
.filter((e) -> Boolean.TRUE.equals(e.getValue()))
// transform entry to key split by regex
.map(e -> e.getKey().split("(?=\\p{Upper})"))
// transform to first array item
.map(a -> a[0])
// print
.forEach(System.out::println);

Set created from complex List

So I have a list containing duplicated entities from database with the same "Id" (it's not the real Id but kind of) but a different CreatedDate.
So I would like to have the latest entity from duplicates with the latest CreatedDate.
Example I have a list of created users :
RealId|CreatedDate|Id|Name
1|20170101|1|User1
2|20170102|1|User1Modified
3|20170103|2|User2
4|20170104|2|User2Modified
From that list what is the best way to obtain :
RealId|CreatedDate|Id|Name
2|20170102|1|User1Modified
4|20170104|2|User2Modified
This is my first idea
List<T> r = query.getResultList();
Set<T> distinct = r.stream().filter(x -> {
List<T> clones = r.stream()
.filter(y -> y.getId() == x.getId())
.collect(Collectors.toList());
T max = clones.stream()
.max(Comparator.comparing(AbstractEntityHistory::getEntryDate))
.get();
return max.getNumber() == x.getNumber();
}).collect(Collectors.toSet());
An other idea I have is to make it order descending by the date then do distinct().collect() like :
Set<T> distinct2 = r.stream().sorted((x,y) -> {
if(x.getEntryDate().isBefore(y.getEntryDate())) {
return 1;
} else if(x.getEntryDate().isAfter(y.getEntryDate())) {
return -1;
} else {
return 0;
}
}).distinct().collect(Collectors.toSet());
Here, T overrides equals which watch for the RealId if they are equal else use reflection to watch every other field.
Try this:
List<YourObject> collect = activities
.stream()
.collect(Collectors.groupingBy(
YourObject::getId,
Collectors.maxBy(Comparator.comparing(YourObject::getCreatedDate))))
.entrySet()
.stream()
.map(e -> e.getValue().get())
.collect(Collectors.toList());
Here is used Collectors.groupingBy to create a Map<Integer, Optional<YourObject>>, grouped by id and most recent createDate. The you get the entrySet for this map and collect it to a List.
Without java8 functional stuff:
Map<Long, Item> map = new HashMap<>();
for (Item item: items) {
Item old = map.get(item.getId());
if (old == null || old.getDate().before(item.getDate())) {
map.put(item.getId(), item);
}
}
List<Item> result = new ArrayList<Item>(map.values());

Categories

Resources