2024/04/08

Guava Collection Utilities: Lists, Sets

Guava 在 Collection interfaces 有對應的 utility class,這些 utilities 是 static method,可直接使用。

Interface JDK or Guava? Corresponding Guava utility class
Collection JDK Collections2
List JDK Lists
Set JDK Sets
SortedSet JDK Sets
Map JDK Maps
SortedMap JDK Maps
Queue JDK Queues
Multiset Guava Multisets
Multimap Guava Multimaps
BiMap Guava Maps
Table Guava Tables

Static Contructor

    @Test
    public void static_constructor() {
        //JDK 的 list 必須建立後再加入元素
        List<String> list = new ArrayList<>();
        list.add("item1");
        list.add("item2");

        // Guava 在建立物件時,可直接填寫 init data
        Set<String> sets = Sets.newHashSet("alpha", "beta", "gamma");
        List<String> list2 = Lists.newArrayList("alpha", "beta", "gamma");

        // Guava 在 init 時,可直接設定 size
        List<String> exactly100 = Lists.newArrayListWithCapacity(100);
        List<String> approx100 = Lists.newArrayListWithExpectedSize(100);
        Set<String> approx100Set = Sets.newHashSetWithExpectedSize(100);

        // Guava 新的 Collection 類別,不提供 constructor,而是提供一個 factory method: create
        Multiset<String> multiset = HashMultiset.create();
    }

Iteratables

Iterables 封裝了 Iterable,提供 fluent 語法

    @Test
    public void iterables() {
        //// concat
        //// concat 可將兩個 collections 連接在一起
        Iterable<Integer> concatenated = Iterables.concat(
                Ints.asList(1, 2, 3),
                Ints.asList(5, 5, 6));
        // concatenated has elements 1, 2, 3, 4, 5, 6
        assertEquals("[1, 2, 3, 5, 5, 6]", concatenated.toString());

        //// concat 在不同類別的 list,不能連接在一起
//        Iterable<Integer> concatenated2 = Iterables.concat(
//                Ints.asList(1, 2, 3),
//                Lists.newArrayList("alpha", "beta", "gamma"));

        //// getFirst: first element, 第二個參數是 預設值
        //// getLast: last element, 失敗時會 throw NoSuchElementException
        Integer firstElement = Iterables.getFirst(concatenated, null);
        Integer lastAdded = Iterables.getLast(concatenated);
        assertEquals(firstElement.intValue(), 1);
        assertEquals(lastAdded.intValue(), 6);

        /// getOnlyElement: the only element in Iterable
        Iterable<Integer> iterable2 = () -> Arrays.asList(100).iterator();
        Iterable<Integer> iterable3 = Collections.singleton(200);
        Exception exception = assertThrows(IllegalArgumentException.class, () -> {
            Integer theElement = Iterables.getOnlyElement(concatenated);
        });
        assertEquals(Iterables.getOnlyElement(iterable2).intValue(), 100);

        //// frequency:  查詢某個 element 出現的次數
        assertEquals(2, Iterables.frequency(concatenated, 5));

        //// partition:  分割成多個 Iterable
        Iterable<List<Integer>> list = Iterables.partition(concatenated, 2);
//        System.out.println("list="+ list);
        assertEquals("[[1, 2], [3, 5], [5, 6]]", list.toString());
        assertEquals("[1, 2]", Iterables.getFirst(list, null).toString());
    }

Iterables 提供跟 Collection 類似的一些 methods

    @Test
    public void iterables_collection_like() {
        // Iterables 提供這些類似 Collection 的 methods
        // 1. addAll
        // 2. contains
        // 3. removeAll
        // 4. retainAll
        // 5. size
        // 6. toArray
        // 7. isEmpty
        // 8. get
        // 9. toString
        ArrayList<Integer> list1 = Lists.newArrayList(1, 2);
        ArrayList<Integer> list2 = Lists.newArrayList(100, 101);
        boolean changed = Iterables.addAll( list1 , list2);
        assertTrue( changed );
        assertEquals("[1, 2, 100, 101]", list1.toString());

        assertTrue( list1.contains(2) );
        assertEquals(list1.size(), 4);
        assertFalse( list1.isEmpty() );

        assertEquals(1, list1.get(0).intValue());
    }

FluentIterable 有幾個 method,可產生 immutable collection

Result Type Method
ImmutableList toList()
ImmutableList toSortedList()
ImmutableSet toSet()
ImmutableSortedSet toSortedSet()
ImmutableMultiset toMultiset()
ImmutableMap toMap()
    @Test
    public void FluentIterable_immutable() {
        // FluentIterable
        ImmutableList<String> list1 =
                FluentIterable.from( Arrays.asList(1,2,3) )
                .transform( Functions.toStringFunction() )
                .limit(10)
                .toList();
        assertEquals( 3, list1.size());
    }

Lists

    @Test
    public void lists() {
        List<Integer> countUp = Ints.asList(1, 2, 3);

        // Lists.reverse: reverse a list
        List<Integer> countDown = Lists.reverse(countUp); // {3, 2, 1}
        // 將 list 以 size 分割成多個 sublist
        List<List<Integer>> parts = Lists.partition(countUp, 2); // {{1, 2}, {3}}

        assertEquals("[1, 2, 3]", countUp.toString());
        assertEquals("[3, 2, 1]", countDown.toString());
        assertEquals("[[1, 2], [3]]", parts.toString());

        // Lists 可產生 ArrayList 及 LinkedList
        // Lists.newArrayList()
        // Lists.newLinkedList()
        List<Integer> list1 = Lists.newArrayList(1,3,2,4);
        List<Integer> list2 = Lists.newLinkedList(Ints.asList(1, 3, 2));
        assertEquals("[1, 3, 2, 4]", list1.toString());
        assertEquals("[1, 3, 2]", list2.toString());

        // 透過 Collections.max 找到最大的元素, Collections.min 最小的元素
        int maxElement = Collections.max(Arrays.asList(1,3,2,4));
        int minElement = Collections.min(Arrays.asList(1,3,2,4));
        assertEquals(4, maxElement);
        assertEquals(1, minElement);
    }

Sets

    @Test
    public void sets() {
        Set<String> set1 = ImmutableSet.of("a", "b", "c");
        Set<String> set2 = ImmutableSet.of("b", "c", "d");

        // 聯集 union of two sets
        Set<String> union1 = Sets.union(set1, set2);
        // 回傳 SetView,可再轉換為 immutable set 使用
        Sets.SetView<String> union2 = Sets.union(set1, set2);
        ImmutableSet<String> immutableSet = union2.immutableCopy();
        assertEquals("[a, b, c, d]", union1.toString());
        assertEquals("[a, b, c, d]", immutableSet.toString());

        // 交集 intersection of two sets
        Sets.SetView<String> intersection = Sets.intersection(set1, set2);
        // I can use intersection as a Set directly, but copying it can be more efficient if I use it a lot.
        assertEquals("[b, c]", intersection.toString());

        // 差集 difference
        Set<String> diff = Sets.difference(set1, set2);
        assertEquals("[a]", diff.toString());

        // symmetricDifference
        Set<String> diff2 = Sets.symmetricDifference(set1, set2);
        assertEquals("[a, d]", diff2.toString());

        // cartesianProduct: Cartesian Product 笛卡兒積
        Set<List<String>> product = Sets.cartesianProduct(set1, set2);
        assertEquals("[[a, b], [a, c], [a, d], [b, b], [b, c], [b, d], [c, b], [c, c], [c, d]]", product.toString());

        // powerSet: 找到所有可能的 subsets
        Set<Set<String>> powerset = Sets.powerSet(set1);
        assertTrue(powerset.contains(ImmutableSet.of("a")));
        assertTrue(powerset.contains(ImmutableSet.of("b")));
        assertTrue(powerset.contains(ImmutableSet.of("a", "b")));
        assertTrue(powerset.contains(ImmutableSet.of("a", "b", "c")));
        assertEquals(8, powerset.size());
    }

References

CollectionUtilitiesExplained · google/guava Wiki · GitHub

沒有留言:

張貼留言