Ba câu trả lời 1 dòng ...
Tôi sẽ sử dụng Google Bộ sưu tập ổi để làm điều này - nếu giá trị của bạn là Comparable
thì bạn có thể sử dụng
valueComparator = Ordering.natural().onResultOf(Functions.forMap(map))
Việc này sẽ tạo một hàm (đối tượng) cho bản đồ [lấy bất kỳ khóa nào làm đầu vào, trả về giá trị tương ứng], sau đó áp dụng thứ tự tự nhiên (có thể so sánh) cho chúng [các giá trị].
Nếu chúng không thể so sánh được, thì bạn sẽ cần phải làm gì đó dọc theo dòng
valueComparator = Ordering.from(comparator).onResultOf(Functions.forMap(map))
Chúng có thể được áp dụng cho TreeMap (dưới dạng Ordering
mở rộng Comparator
) hoặc LinkedHashMap sau khi sắp xếp
Lưu ý : Nếu bạn định sử dụng TreeMap, hãy nhớ rằng nếu so sánh == 0, thì mục đó đã có trong danh sách (điều này sẽ xảy ra nếu bạn có nhiều giá trị so sánh giống nhau). Để giảm bớt điều này, bạn có thể thêm khóa của mình vào bộ so sánh như vậy (giả sử rằng các khóa và giá trị của bạn là Comparable
):
valueComparator = Ordering.natural().onResultOf(Functions.forMap(map)).compound(Ordering.natural())
= Áp dụng thứ tự tự nhiên cho giá trị được ánh xạ bởi khóa và kết hợp với thứ tự tự nhiên của khóa
Lưu ý rằng điều này sẽ vẫn không hoạt động nếu các khóa của bạn so với 0, nhưng điều này là đủ cho hầu hết comparable
các mục (như hashCode
, equals
và compareTo
thường được đồng bộ hóa ...)
Xem Ordering.onResultOf () và Hàm.forMap () .
Thực hiện
Vì vậy, bây giờ chúng ta đã có một bộ so sánh làm những gì chúng ta muốn, chúng ta cần nhận được kết quả từ nó.
map = ImmutableSortedMap.copyOf(myOriginalMap, valueComparator);
Bây giờ điều này rất có thể sẽ làm việc, nhưng:
- cần phải được thực hiện cho một bản đồ hoàn thành
- Đừng thử các so sánh ở trên trên
TreeMap
; Không có điểm nào cố gắng so sánh một khóa được chèn khi nó không có giá trị cho đến sau khi đặt, tức là, nó sẽ bị hỏng rất nhanh
Điểm 1 là một chút phá vỡ đối với tôi; bộ sưu tập google cực kỳ lười biếng (điều này rất tốt: bạn có thể thực hiện khá nhiều thao tác ngay lập tức; công việc thực sự được thực hiện khi bạn bắt đầu sử dụng kết quả) và điều này đòi hỏi phải sao chép toàn bộ bản đồ!
Câu trả lời "Đầy đủ" / Bản đồ được sắp xếp trực tiếp theo các giá trị
Đừng lo lắng mặc dù; nếu bạn bị ám ảnh đủ với việc sắp xếp một bản đồ "sống" theo cách này, bạn có thể giải quyết không chỉ một mà cả hai (!) các vấn đề trên với một thứ điên rồ như sau:
Lưu ý: Điều này đã thay đổi đáng kể vào tháng 6 năm 2012 - mã trước đó không bao giờ có thể hoạt động: HashMap nội bộ được yêu cầu để tra cứu các giá trị mà không tạo vòng lặp vô hạn giữa TreeMap.get()
-> compare()
và compare()
->get()
import static org.junit.Assert.assertEquals;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import com.google.common.base.Functions;
import com.google.common.collect.Ordering;
class ValueComparableMap<K extends Comparable<K>,V> extends TreeMap<K,V> {
//A map for doing lookups on the keys for comparison so we don't get infinite loops
private final Map<K, V> valueMap;
ValueComparableMap(final Ordering<? super V> partialValueOrdering) {
this(partialValueOrdering, new HashMap<K,V>());
}
private ValueComparableMap(Ordering<? super V> partialValueOrdering,
HashMap<K, V> valueMap) {
super(partialValueOrdering //Apply the value ordering
.onResultOf(Functions.forMap(valueMap)) //On the result of getting the value for the key from the map
.compound(Ordering.natural())); //as well as ensuring that the keys don't get clobbered
this.valueMap = valueMap;
}
public V put(K k, V v) {
if (valueMap.containsKey(k)){
//remove the key in the sorted set before adding the key again
remove(k);
}
valueMap.put(k,v); //To get "real" unsorted values for the comparator
return super.put(k, v); //Put it in value order
}
public static void main(String[] args){
TreeMap<String, Integer> map = new ValueComparableMap<String, Integer>(Ordering.natural());
map.put("a", 5);
map.put("b", 1);
map.put("c", 3);
assertEquals("b",map.firstKey());
assertEquals("a",map.lastKey());
map.put("d",0);
assertEquals("d",map.firstKey());
//ensure it's still a map (by overwriting a key, but with a new value)
map.put("d", 2);
assertEquals("b", map.firstKey());
//Ensure multiple values do not clobber keys
map.put("e", 2);
assertEquals(5, map.size());
assertEquals(2, (int) map.get("e"));
assertEquals(2, (int) map.get("d"));
}
}
Khi chúng tôi đặt, chúng tôi đảm bảo rằng bản đồ băm có giá trị cho bộ so sánh, và sau đó đặt vào TreeSet để sắp xếp. Nhưng trước đó chúng tôi kiểm tra bản đồ băm để thấy rằng khóa không thực sự là một bản sao. Ngoài ra, bộ so sánh mà chúng tôi tạo cũng sẽ bao gồm khóa để các giá trị trùng lặp không xóa các khóa không trùng lặp (do == so sánh). Hai mục này rất quan trọng để đảm bảo giữ hợp đồng bản đồ; nếu bạn nghĩ rằng bạn không muốn điều đó, thì bạn gần như hoàn toàn đảo ngược bản đồ (sang Map<V,K>
).
Hàm tạo sẽ cần được gọi là
new ValueComparableMap(Ordering.natural());
//or
new ValueComparableMap(Ordering.from(comparator));
List<Map.Entry<...>> list =new LinkedList(map.entrySet())
vàCollections.sort ....
theo cách đó.