Reputation: 57
So I am trying to sort a multimap in Java, here's what the maps looks like:
Map<Integer, Pair<Double, Color>> inputMap;
Map<Integer, Pair<Double, Color>> outputMap;
and here is my Pair class:
class Pair<Double, Color> {
public final Double x;
public final Color y;
public Pair(Double x, Color y) {
this.x = x;
this.y = y;
}
}
I am trying to sort it by the first item of Pair. I tried to use something like this:
outputMap = new TreeMap<>(inputMap);
but that doesn't exactly work how I thought it would... It doesn't seem to sort it at all.
How would I sort the map by Pair.X?
Upvotes: 1
Views: 1965
Reputation: 6803
All SortedMap implementations (including TreeMap
) sort by the key
not by value
.
https://docs.oracle.com/javase/7/docs/api/java/util/SortedMap.html
A Map that further provides a total ordering on its keys.
Sorting the Map
internally by value
also would be bad for the performance which is optimised for access through the key
.
A Map
only ever associates one value to each key.
This becomes especially clear when you look at the documentation of put
Associates the specified value with the specified key in this map (optional operation). If the map previously contained a mapping for the key, the old value is replaced by the specified value.
So what you defined with Map<Integer, Pair<Double, Color>>
is not even a MultiMap. Which explains why it does not behave how you expect it to.
What you are looking for is a SortedSetMultimap
A SetMultimap whose set of values for a given key are kept sorted; that is, they comprise a SortedSet.
With
//Class renamed to reflect what it actually is, to avoid conflicts with other Pairs. Also you don't need generics then, which you did not use any way.
class ColorPair implements Comparable {
public final Double x;
public final Color y;
public ColorPair (Double x, Color y) {
this.x = x;
this.y = y;
}
//compares only the first component of the Pair
public int compareTo(ColorPair other){
return Double.compare(x, other.x)
}
}
Then you can create the SortedSetMultimap with
TreeMultimap<Integer, ColorPair> sortedSetMap = new TreeMultimap<>() `
and fill it with the ColorPair
s
Upvotes: 3
Reputation: 7917
Highlight
You can sort the map using:
Map<Integer, Pair<Double, Color>> sortedMap = map.entrySet().stream()
.sorted(Comparator.comparingDouble(e -> e.getValue().x))
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(p1, p2) -> p1,
LinkedHashMap::new));
Full code
public static void main(String[] args) {
new MyClass().test();
}
public void test() {
Map<Integer, Pair<Double, Color>> map = Map.of(
1, new Pair<>(1.0, Color.BLACK),
2, new Pair<>(3.0, Color.RED),
3, new Pair<>(2.0, Color.BLUE));
Map<Integer, Pair<Double, Color>> sortedMap = map.entrySet().stream()
.sorted(Comparator.comparingDouble(e -> e.getValue().x))
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(p1, p2) -> p1,
LinkedHashMap::new));
System.out.println(sortedMap);
}
class Pair<Double, Color> {
public final Double x;
public final Color y;
public Pair(Double x, Color y) {
this.x = x;
this.y = y;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Pair<?, ?> pair = (Pair<?, ?>) o;
return Objects.equals(x, pair.x) &&
Objects.equals(y, pair.y);
}
@Override
public int hashCode() {
return Objects.hash(x, y);
}
@Override
public String toString() {
return "Pair{" +
"x=" + x +
", y=" + y +
'}';
}
}
Output
{1=Pair{x=1.0, y=java.awt.Color[r=0,g=0,b=0]}, 3=Pair{x=2.0, y=java.awt.Color[r=0,g=0,b=255]}, 2=Pair{x=3.0, y=java.awt.Color[r=255,g=0,b=0]}}
Upvotes: 0
Reputation: 1829
You can't sort by map values - by keys only.
If you need both - HashMap for O(1) access to objects and sorted traversal - create a sorted list and keep same objects there.
List<Pair<Double, Object>>outputList = inputMap.values().stream().sorted((o1, o2) -> 0 /*IMPLEMENT_COMPARATOR_HERE*/).collect(Collectors.toList());
If the map is mutable - it would be better to create a class that will contain both - map and list - and provide methods like "add" "get" and "remove". Direct access to those structures should be avoided.
Don't forget to synchronize operations on both data structures to make your code thread safe.
Upvotes: 1