คำตอบ 1 บรรทัดสามคำ ...
ฉันจะใช้Google Collections Guavaเพื่อทำสิ่งนี้ - ถ้าคุณมีค่าComparable
คุณก็สามารถใช้ได้
valueComparator = Ordering.natural().onResultOf(Functions.forMap(map))
ซึ่งจะสร้างฟังก์ชั่น (วัตถุ) สำหรับแผนที่ [ที่ใช้คีย์ใด ๆ เป็นอินพุตป้อนคืนค่าที่เกี่ยวข้อง] จากนั้นใช้การเรียงลำดับตามธรรมชาติ (เทียบเคียง) กับพวกเขา [ค่า]
หากพวกเขาไม่เทียบเท่าคุณจะต้องทำอะไรบางอย่างตามแนวของ
valueComparator = Ordering.from(comparator).onResultOf(Functions.forMap(map))
สิ่งเหล่านี้อาจนำไปใช้กับ TreeMap (ตามที่Ordering
ขยายComparator
) หรือLinkedHashMap หลังจากการเรียงลำดับบางอย่าง
หมายเหตุ : หากคุณจะใช้ TreeMap โปรดจำไว้ว่าหากมีการเปรียบเทียบ == 0 รายการนั้นจะอยู่ในรายการแล้ว (ซึ่งจะเกิดขึ้นหากคุณมีหลายค่าที่เปรียบเทียบเหมือนกัน) ในการบรรเทาปัญหานี้คุณสามารถเพิ่มคีย์ของคุณลงในเครื่องมือเปรียบเทียบได้ (สมมติว่าคีย์และค่าของคุณเป็นComparable
ดังนี้):
valueComparator = Ordering.natural().onResultOf(Functions.forMap(map)).compound(Ordering.natural())
= ใช้การเรียงแบบเป็นธรรมชาติกับค่าที่แมปด้วยคีย์และสารประกอบที่มีการเรียงลำดับตามธรรมชาติของคีย์
หมายเหตุว่านี้จะยังคงไม่ทำงานถ้าคีย์ของคุณเปรียบเทียบกับ 0 แต่เรื่องนี้ควรจะเพียงพอสำหรับส่วนมากcomparable
รายการ (ตามhashCode
, equals
และcompareTo
มักจะอยู่ในซิงค์ ... )
ดูOrdering.onResultOf ()และFunctions.forMap ()
การดำเนินงาน
ดังนั้นตอนนี้เรามีผู้เปรียบเทียบที่ทำสิ่งที่เราต้องการเราต้องได้รับผลจากมัน
map = ImmutableSortedMap.copyOf(myOriginalMap, valueComparator);
ตอนนี้สิ่งนี้จะทำงานได้ แต่:
- จำเป็นต้องทำตามแผนที่เสร็จสมบูรณ์
- อย่าพยายาม comparators ดังกล่าวข้างต้นที่
TreeMap
; ไม่มีจุดใดที่พยายามเปรียบเทียบคีย์ที่ถูกแทรกเมื่อมันไม่มีค่าจนกระทั่งหลังจากที่ใส่นั่นคือมันจะแตกเร็วมาก
จุดที่ 1 เป็นข้อตกลงที่ดีสำหรับฉัน คอลเลคชั่น google ขี้เกียจอย่างไม่น่าเชื่อ (ซึ่งก็ดี: คุณสามารถทำทุกอย่างได้อย่างรวดเร็วในทันทีการทำงานจริงจะเกิดขึ้นเมื่อคุณเริ่มใช้ผลลัพธ์) และต้องคัดลอกแผนที่ทั้งหมด !
คำตอบ "เต็ม" / แผนที่เรียงสดตามค่า
อย่ากังวลไป หากคุณหมกมุ่นอยู่กับการมีแผนที่ "สด" เรียงลำดับในลักษณะนี้คุณสามารถแก้ปัญหาไม่ได้ทั้งคู่ (!) จากปัญหาด้านบนด้วยสิ่งที่บ้าคลั่งดังต่อไปนี้:
หมายเหตุ: สิ่งนี้มีการเปลี่ยนแปลงอย่างมากในเดือนมิถุนายน 2012 - รหัสก่อนหน้านี้ไม่สามารถใช้งานได้: ต้องใช้ HashMap ภายในเพื่อค้นหาค่าโดยไม่ต้องสร้างวงวนไม่สิ้นสุดระหว่างTreeMap.get()
-> compare()
และ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"));
}
}
เมื่อเราใส่เรามั่นใจว่าแผนที่แฮชมีค่าสำหรับตัวเปรียบเทียบแล้วใส่ลงใน TreeSet สำหรับการเรียงลำดับ แต่ก่อนหน้านั้นเราตรวจสอบแผนที่แฮชเพื่อดูว่ารหัสนั้นไม่ได้ซ้ำกันจริง ๆ นอกจากนี้ตัวเปรียบเทียบที่เราสร้างจะรวมคีย์ไว้ด้วยเพื่อที่ค่าที่ซ้ำกันจะไม่ลบคีย์ที่ไม่ซ้ำกัน (เนื่องจากการเปรียบเทียบ ==) 2 รายการเหล่านี้มีความสำคัญในการรับรองสัญญาแผนที่ หากคุณคิดว่าคุณไม่ต้องการสิ่งนั้นแสดงว่าคุณเกือบถึงจุดที่จะกลับแผนที่ทั้งหมด (เป็นMap<V,K>
)
ตัวสร้างจะต้องถูกเรียกว่าเป็น
new ValueComparableMap(Ordering.natural());
//or
new ValueComparableMap(Ordering.from(comparator));
List<Map.Entry<...>> list =new LinkedList(map.entrySet())
และCollections.sort ....
เป็นอย่างนั้น