簡體   English   中英

Java 8集合映射從集合中刪除元素,如果為空則刪除條目

[英]Java 8 Map of Collections remove element from collection and remove entry if empty

我有一個地圖,其值是一個集合。 給定一個鍵,我想刪除該集合的一個元素並將其返回,但如果該集合為空,我還想刪除該條目。 有沒有辦法使用Java 8的眾多新Map方法之一以簡短的方式完成此操作?

一個簡單的例子(我使用Stack但它可以是List,Set等)。 為了示例,我們假設已經檢查了地圖包含密鑰。

public static String removeOne(Map<Integer, Stack<String>> map, int key) {
    Stack<String> stack = map.get(key);
    String result = stack.pop();
    if(stack.isEmpty()){
        map.remove(key);
    }
    return result;
}

我試過做類似的事情

map.compute(1, (k, v) -> {v.pop(); return v.size() == 0 ? null : v;});

但即使它確實刪除了條目,如果為空,我不知道如何獲取pop()返回的值。

嗯,它甚至比你現有的還要丑陋,但是有一種方法,我想:

public static String removeOne(Map<Integer, Stack<String>> map, int key) {
    String[] removed = new String[1];
    map.compute(key, (k, v) -> {
        removed[0] = v.pop();
        return v.size() == 0 ? null : v;
    });
    return removed[0];
}

問題是merge/compute等返回 ,在您的情況下是Stack/Set/List ,而不是該集合中的單個元素。

或者您可以使用size重寫它:

public static String removeOne(Map<Integer, Stack<String>> map, int key) {
    return map.get(key).size() == 1 ? map.remove(key).pop() : map.get(key).pop();
}

有沒有辦法使用Java 8的眾多新Map方法之一以簡短的方式完成此操作?

JDK8沒有新方法可以改善您的代碼,無論是在可讀性還是高效方面。

如果你這樣做是為了鍛煉你自己,那么我可以在某種程度上理解為什么你想要縮短代碼( 如果可能的話 )但是當涉及到生產代碼時應該避免打高爾夫球,而是采用那種方法最具可讀性和可維護性; 沒關系,如果它更長。

你的方法很好。

Guava的Multimap為您處理remove-collection-if-empty邏輯。 您可以在兩行中獲得與方法相同的行為:

public static String removeOne(ListMultimap<Integer, String> map, int key) {
    List<String> stack = map.get(key);
    return stack.remove(stack.size() - 1);
}

如果映射沒有給定鍵的條目,則現有解決方案和上述解決方案都會拋出異常。 您可以選擇更改代碼來處理此問題:

public static String removeOne(ListMultimap<Integer, String> map, int key) {
    List<String> stack = map.get(key);
    if (stack.isEmpty()) {
        return null;
    }
    return stack.remove(stack.size() - 1);
}

當然,你可以使這個通用:

public static <K, V> V removeOne(ListMultimap<K, V> map, K key) {
    List<V> stack = map.get(key);
    if (stack.isEmpty()) {
        return null;
    }
    return stack.remove(stack.size() - 1);
}

我完全贊同@NicholasK。 這里沒有理由使用任何流或lambdas。

你的方法非常好。 我想要添加的唯一內容是將其設為通用:

public static <K, E, C extends Collection<E>> E removeOne(Map<K, C> map, K key) {
    C col = map.get(key);
    Iterator<E> it = col.iterator();
    E e = it.next();
    it.remove();
    if (!it.hasNext()) {
        map.remove(key);
    }
    return e;
}

此方法適用於返回有效迭代器的任何集合(映射值)。

/* quite ugly
String rv = Optional.ofNullable(map.get(1)).map(stack -> {
            if (!stack.isEmpty()) {
                String v = stack.pop();
                if (stack.isEmpty()) {
                    map.remove(1);
                }
                return v;
            }
            return null;
        }).orElse(null);
*/ 

@Test
public void test() {
    {
        Map<Integer, Stack<String>> map = new HashMap<>();
        Stack<String> s = new Stack<String>();
        s.addAll(Arrays.asList("a", "b"));
        map.put(1, s);
        String rv = Optional.ofNullable(map.get(1)).map(stack -> {
            if (!stack.isEmpty()) {
                String v = stack.pop();
                if (stack.isEmpty()) {
                    map.remove(1);
                }
                return v;
            }
            return null;
        }).orElse(null);
        Assert.assertEquals("b", rv);
        Assert.assertEquals(1, map.get(1).size());
        Assert.assertEquals("a", map.get(1).iterator().next());
    }
    {
        Map<Integer, Stack<String>> map = new HashMap<>();
        Stack<String> s = new Stack<String>();
        s.add("a");
        map.put(1, s);
        String rv = Optional.ofNullable(map.get(1)).map(stack -> {
            if (!stack.isEmpty()) {
                String v = stack.pop();
                if (stack.isEmpty()) {
                    map.remove(1);
                }
                return v;
            }
            return null;
        }).orElse(null);
        Assert.assertEquals("a", rv);
        Assert.assertNull(map.get(1));
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM