BiMap
JDK 的方式,只能用兩個 Maps 分別儲存,並自己維護同步資料
BiMap 就是 Map<K,V>
提供 inverse(),可取得 Map<V, K>
為了提供 inverse(),values 必須要唯一,values() 可得到 Set
@Test
public void biMap() {
// JDK 的方式,兩個 Map 獨立
Map<String, Integer> nameToId = Maps.newHashMap();
Map<Integer, String> idToName = Maps.newHashMap();
nameToId.put("Bob", 42);
idToName.put(42, "Bob");
BiMap<String, Integer> userIdNameBiMap = HashBiMap.create();
userIdNameBiMap.put("Bob", 42);
userIdNameBiMap.put("Alice", 43);
System.out.println("");
System.out.println("userIdNameBiMap: "+userIdNameBiMap);
String userForId = userIdNameBiMap.inverse().get(42);
System.out.println("user 42 ForId: "+userForId);
// userIdNameBiMap: {Bob=42, Alice=43}
// user 42 ForId: Bob
}
implementations
Key-Value Map Impl | Value-Key Map Impl | Corresponding BiMap |
---|---|---|
HashMap |
HashMap |
HashBiMap |
ImmutableMap |
ImmutableMap |
ImmutableBiMap |
EnumMap |
EnumMap |
EnumBiMap |
EnumMap |
HashMap |
EnumHashBiMap |
Table
ref: Guide to Guava Table | Baeldung
@Test
public void table_create() {
// HashBasedTable.create()
// 內部使用 LinkedHashMap
Table<String, String, Integer> universityCourseSeatTable
= HashBasedTable.create();
// 內部使用 TreeMap,natural ordering
Table<String, String, Integer> universityCourseSeatTableOrdered
= TreeBasedTable.create();
// table size 固定時,可使用 ArrayTable
List<String> universityRowTable
= Lists.newArrayList("Mumbai", "Harvard");
List<String> courseColumnTables
= Lists.newArrayList("Chemical", "IT", "Electrical");
Table<String, String, Integer> universityCourseSeatTableArrayTable
= ArrayTable.create(universityRowTable, courseColumnTables);
// ImmutableTable: immutable table
Table<String, String, Integer> universityCourseSeatTableImmutable
= ImmutableTable.<String, String, Integer> builder()
.put("Mumbai", "Chemical", 120).build();
}
@Test
public void table_using() {
Table<String, String, Integer> universityCourseSeatTable
= HashBasedTable.create();
universityCourseSeatTable.put("Mumbai", "Chemical", 120);
universityCourseSeatTable.put("Mumbai", "IT", 60);
universityCourseSeatTable.put("Harvard", "Electrical", 60);
universityCourseSeatTable.put("Harvard", "IT", 120);
// get 可取得 row, col 對應的資料
int seatCount = universityCourseSeatTable.get("Mumbai", "IT");
Integer seatCountForNoEntry = universityCourseSeatTable.get("Oxford", "IT");
assertEquals(seatCount, 60);
assertNull(seatCountForNoEntry);
////////////
// containsXXX 可判斷是否存在
// 1. row key
// 2. col key
// 3. row, col
// 4 value
boolean entryIsPresent
= universityCourseSeatTable.contains("Mumbai", "IT");
boolean courseIsPresent
= universityCourseSeatTable.containsColumn("IT");
boolean universityIsPresent
= universityCourseSeatTable.containsRow("Mumbai");
boolean seatCountIsPresent
= universityCourseSeatTable.containsValue(60);
assertTrue(entryIsPresent);
assertTrue(courseIsPresent);
assertTrue(universityIsPresent);
assertTrue(seatCountIsPresent);
///////
// 由 col 取得 row, value 的 Map
Map<String, Integer> universitySeatMap
= universityCourseSeatTable.column("IT");
assertEquals(universitySeatMap.size(), 2);
assertEquals(universitySeatMap.get("Mumbai").intValue(), 60);
assertEquals(universitySeatMap.get("Harvard").intValue(), 120);
/////
// columnMap 取得 Map<UniversityName, Map<CoursesOffered, SeatAvailable>>
Map<String, Map<String, Integer>> courseKeyUniversitySeatMap
= universityCourseSeatTable.columnMap();
assertEquals(courseKeyUniversitySeatMap.size(), 3);
assertEquals(courseKeyUniversitySeatMap.get("IT").size(), 2);
assertEquals(courseKeyUniversitySeatMap.get("Electrical").size(), 1);
assertEquals(courseKeyUniversitySeatMap.get("Chemical").size(), 1);
///////
// 由 row 取得 col, value 的 Map
Map<String, Integer> courseSeatMap
= universityCourseSeatTable.row("Mumbai");
assertEquals(courseSeatMap.size(), 2);
assertEquals(courseSeatMap.get("IT").intValue(), 60);
assertEquals(courseSeatMap.get("Chemical").intValue(), 120);
//////
// rowKeySet: row keys
// columnKeySet: col keys
Set<String> universitySet = universityCourseSeatTable.rowKeySet();
assertEquals(universitySet.size(), 2);
Set<String> courseSet = universityCourseSeatTable.columnKeySet();
assertEquals(courseSet.size(), 3);
/////////
// remove 會回傳既有的 value 後,移除該 row, col 的 value
Integer seatCount2 = universityCourseSeatTable.remove("Mumbai", "IT");
Integer seatCount3 = universityCourseSeatTable.remove("Mumbai", "IT");
assertEquals(seatCount2.intValue(), 60);
assertNull(seatCount3);
}
ClassToInstanceMap
ClassToInstanceMap 是一種特殊的 Map,可確保 keys, values 都是 B 的子類別
ClassToInstanceMap extends Map 介面,並增加兩個 methods: T getInstance(Class) and T putInstance(Class, T) ,這兩個 method 有做型別檢查,並避免 casting
@Test
public void create() {
// 產生 ImmutableClassToInstanceMap
// 1. using the of() method to create an empty map
ImmutableClassToInstanceMap map1 = ImmutableClassToInstanceMap.of();
// 2. using the of(Class<T> type, T value) method to create a single entry map
ImmutableClassToInstanceMap map2 = ImmutableClassToInstanceMap.of(Save.class, new Save());
// 3. copyOf() 複製另一個 ImmutableClassToInstanceMap
ImmutableClassToInstanceMap map3 = ImmutableClassToInstanceMap.copyOf(map2);
// 4. builder
ImmutableClassToInstanceMap map4 = ImmutableClassToInstanceMap
.<Action>builder()
.put(Save.class, new Save())
.put(Delete.class, new Delete())
.build();
////////
// MutableClassToInstanceMap
// 1. create()
MutableClassToInstanceMap mmap1 = MutableClassToInstanceMap.create();
// 2. create(Map<Class<? extends B>, B> backingMap)
MutableClassToInstanceMap mmap2 = MutableClassToInstanceMap.create(new HashMap());
}
interface Action {
}
class Save implements Action {
}
class Delete implements Action {
}
@Test
public void using() {
// 增加兩個 method 到 Map interface
MutableClassToInstanceMap map = MutableClassToInstanceMap
.create();
map.put(Save.class, new Save());
map.put(Delete.class, new Delete());
// 1. <T extends B> T getInstance(Class<T> type):
Action saveAction = (Action) map.get(Save.class);
Delete deleteAction = (Delete) map.getInstance(Delete.class);
// 2. <T extends B> T putInstance(Class<T> type, @Nullable T value):
Action newOpen = (Action) map.put(Save.class, new Save());
Delete newDelete = (Delete) map.putInstance(Delete.class, new Delete());
}
RangeSet
a set comprising of zero or more non-empty, disconnected ranges
最基本實作 RangeSet 的類別為 TreeRangeSet
@Test
public void create() {
// 1. 直接用 create 產生一個空的 RangeSet
RangeSet<Integer> numberRangeSet = TreeRangeSet.create();
// 2. create 時,加上一個 List of Range 參數
List<Range<Integer>> numberList = Arrays.asList(Range.closed(0, 2));
RangeSet<Integer> numberRangeSet2 = TreeRangeSet.create(numberList);
// ImmutableRangeSet 的 builder 產生 ImmutableRangeSet
// ImmutableRangeSet.Builder<Integer> builder = ImmutableRangeSet.builder();
RangeSet<Integer> numberRangeSet3
= new ImmutableRangeSet.Builder<Integer>().add(Range.closed(0, 2)).build();
}
@Test
public void add_remove_range() {
// add/remove range
RangeSet<Integer> numberRangeSet = TreeRangeSet.create();
numberRangeSet.add(Range.closed(0, 2));
numberRangeSet.add(Range.closed(3, 5));
numberRangeSet.add(Range.closed(6, 8));
numberRangeSet.add(Range.closed(9, 15));
numberRangeSet.remove(Range.closed(3, 5));
numberRangeSet.remove(Range.closed(7, 10));
assertTrue(numberRangeSet.contains(1));
assertFalse(numberRangeSet.contains(9));
assertTrue(numberRangeSet.contains(12));
}
@Test
public void range_span() {
RangeSet<Integer> numberRangeSet = TreeRangeSet.create();
numberRangeSet.add(Range.closed(0, 2));
numberRangeSet.add(Range.closed(3, 5));
numberRangeSet.add(Range.closed(6, 8));
Range<Integer> experienceSpan = numberRangeSet.span();
assertEquals(0, experienceSpan.lowerEndpoint().intValue());
assertEquals(8, experienceSpan.upperEndpoint().intValue());
}
@Test
public void subrange() {
RangeSet<Integer> numberRangeSet = TreeRangeSet.create();
numberRangeSet.add(Range.closed(0, 2));
numberRangeSet.add(Range.closed(3, 5));
numberRangeSet.add(Range.closed(6, 8));
RangeSet<Integer> numberSubRangeSet
= numberRangeSet.subRangeSet(Range.closed(4, 14));
assertFalse(numberSubRangeSet.contains(3));
assertFalse(numberSubRangeSet.contains(14));
assertTrue(numberSubRangeSet.contains(7));
}
@Test
public void complement() {
RangeSet<Integer> numberRangeSet = TreeRangeSet.create();
numberRangeSet.add(Range.closed(0, 2));
numberRangeSet.add(Range.closed(3, 5));
numberRangeSet.add(Range.closed(6, 8));
RangeSet<Integer> numberRangeComplementSet
= numberRangeSet.complement();
assertTrue(numberRangeComplementSet.contains(-1000));
assertFalse(numberRangeComplementSet.contains(2));
assertFalse(numberRangeComplementSet.contains(3));
assertTrue(numberRangeComplementSet.contains(1000));
}
@Test
public void intersect() {
RangeSet<Integer> numberRangeSet = TreeRangeSet.create();
numberRangeSet.add(Range.closed(0, 2));
numberRangeSet.add(Range.closed(3, 10));
numberRangeSet.add(Range.closed(15, 18));
assertTrue(numberRangeSet.intersects(Range.closed(4, 17)));
assertFalse(numberRangeSet.intersects(Range.closed(19, 200)));
}
RangeMap
mapping 不連續非空的 ranges 到非 null 的 values
基本實作為TreeRangeMap
@Test
public void create() {
// 用 TreeRangeMap 的 create 產生 mutable RangeMap
RangeMap<Integer, String> experienceRangeDesignationMap = TreeRangeMap.create();
// ImmutableRangeMap.Builder 產生 ImmutableRangeMap
RangeMap<Integer, String> experienceRangeDesignationMap2 =
new ImmutableRangeMap.Builder<Integer, String>()
.put(Range.closed(0, 2), "Junior")
.build();
}
@Test
public void query_within_range() {
RangeMap<Integer, String> experienceRangeDesignationMap
= TreeRangeMap.create();
experienceRangeDesignationMap.put(
Range.closed(0, 2), "Junior");
experienceRangeDesignationMap.put(
Range.closed(3, 5), "Senior");
experienceRangeDesignationMap.put(
Range.closed(6, 8), "College");
experienceRangeDesignationMap.put(
Range.closed(9, 15), "Research");
assertEquals("College",
experienceRangeDesignationMap.get(6));
assertEquals("Research",
experienceRangeDesignationMap.get(15));
assertNull(experienceRangeDesignationMap.get(30));
}
@Test
public void remove_rage() {
RangeMap<Integer, String> experienceRangeDesignationMap
= TreeRangeMap.create();
experienceRangeDesignationMap.put(
Range.closed(0, 2), "Junior");
experienceRangeDesignationMap.put(
Range.closed(3, 5), "Senior");
experienceRangeDesignationMap.put(
Range.closed(6, 8), "College");
experienceRangeDesignationMap.put(
Range.closed(9, 15), "Research");
experienceRangeDesignationMap.remove(Range.closed(9, 15));
experienceRangeDesignationMap.remove(Range.closed(1, 4));
assertNull(experienceRangeDesignationMap.get(9));
assertEquals("Junior",
experienceRangeDesignationMap.get(0));
assertEquals("Senior",
experienceRangeDesignationMap.get(5));
assertNull(experienceRangeDesignationMap.get(1));
}
@Test
public void span() {
RangeMap<Integer, String> experienceRangeDesignationMap
= TreeRangeMap.create();
experienceRangeDesignationMap.put(
Range.closed(0, 2), "Junior");
experienceRangeDesignationMap.put(
Range.closed(3, 5), "Senior");
experienceRangeDesignationMap.put(
Range.closed(6, 8), "College");
experienceRangeDesignationMap.put(
Range.closed(9, 15), "Research");
Range<Integer> experienceSpan = experienceRangeDesignationMap.span();
assertEquals(0, experienceSpan.lowerEndpoint().intValue());
assertEquals(15, experienceSpan.upperEndpoint().intValue());
}
@Test
public void subRageMap() {
RangeMap<Integer, String> experienceRangeDesignationMap
= TreeRangeMap.create();
experienceRangeDesignationMap.put(
Range.closed(0, 2), "Junior");
experienceRangeDesignationMap.put(
Range.closed(3, 5), "Senior");
experienceRangeDesignationMap.put(
Range.closed(6, 8), "College");
experienceRangeDesignationMap.put(
Range.closed(9, 15), "Research");
RangeMap<Integer, String> experiencedSubRangeDesignationMap
= experienceRangeDesignationMap.subRangeMap(Range.closed(4, 14));
assertNull(experiencedSubRangeDesignationMap.get(3));
assertTrue(experiencedSubRangeDesignationMap.asMapOfRanges().values()
.containsAll(Arrays.asList("Senior", "College", "Research")));
}
沒有留言:
張貼留言