Use the Power of Objects
hashmap looks like {"Start":"A", "End":"B","Length":5}
You are misusing Maps, it definitely should be a custom object, with attributes having proper types instead of storing them as java.lang.Object
in the map.
For example, that how it might look like, if we implemented as a Java 16 record:
public record Foo(String start, String end,int length) {}
Now things would be simple, instead of a nested collection you would have a list of Foo
.
Find a single Max element
To find a Foo
with maximum length
you can use either Stream.max()
or Collections.max()
, both expect an instance of Comparator
as an argument.
List<Foo> foos = // intializing the list
// with Stream API
Foo max = foos.stream()
.max(Comparator.comparingInt(Foo::length)) // produces Optional<Foo>
.orElseThrow();
// using Collections.max()
Foo max = Collections.max(foos, Comparator.comparingInt(Foo::length));
Find a group of elements
If you want to obtain a Collection of objects having the largest value of length
, then it would require a bit more effort.
For that can group the data by length
into an intermediate Map by using Collector groupingBy()
, then create a stream over map entries and pick the entry with the highest key using Stream.max()
(like it has been done above):
List<Foo> foos = // intializing the list
List<Foo> max = foos.stream()
.collect(Collectors.groupingBy(Foo::length)) // Map<Integer, List<Foo>>
.entrySet().stream() // Stream<Map.Entry<Integer, List<Foo>>>
.max(Map.Entry.comparingByKey()) // Optional<Map.Entry<Integer, Foo>>
.map(Map.Entry::getValue) // Optional<List<Foo>>
.orElse(Collections.emptyList());
Alternatively, it can be done without creating an intermediate Map and the second stream over its entries.
To achieve that we can use the three-args version of Stream.collect()
and accumulate stream elements into a list that would be returned as the result of the stream execution:
List<Foo> foos = // intializing the list
List<Foo> max = foos.stream()
.collect(
ArrayList::new,
(List<Foo> l, Foo f) -> {
if (!l.isEmpty() && l.get(0).length() < f.length()) l.clear();
if (l.isEmpty() || l.get(0).length() == f.length()) l.add(f);
},
(l, r) -> {
if (l.get(0).length() < r.get(0).length()) l.clear();
if (l.isEmpty() || l.get(0).length() == r.get(0).length()) l.addAll(r);
}
);
Sidenote: you might also want to learn What does it mean to "program to an interface"?