【问题标题】:How to get a specific Map.Entry<K, V> for a specific key?如何获取特定键的特定 Map.Entry<K, V>?
【发布时间】:2022-08-15 21:20:54
【问题描述】:

我正在用 Java 实现 NavigableMap-implementing LinkedHashMap。 (似乎没有很多(任何?)原因为什么LinkedHashMap 没有实现NavigableMap,但我离题了......)

我已经通过迭代entrySet() 编写了lowerKey()lowerEntry()higherKey()higherEntry()。在这些情况下,我看不到任何方法可以避免迭代整个 entrySet()

对于floorKey()floorEntry()ceilingKey()ceilingEntry(),在密钥存在的情况下,考虑到我已经可以获得值,我想避免迭代entrySet()的费用与普通的get()

有没有办法获取特定键的Map.Entry,而不仅仅是值?谢谢。

  • LinkedHashMap 实现 NavigableMap 没有意义,因为它没有排序 - 它是按插入顺序排序的。除非您对LinkedHashMap 有其他概念?
  • NavigableMap 的合同似乎取决于 Map订购, 不是排序的.
  • 你知道NavigableMap 继承自SortedMap 吗?
  • 我没有注意到这一点,但这并没有真正影响我的目的。
  • 此外,即使SortedMap 似乎也依赖于订购而且不一定排序.

标签: java subclassing linkedhashmap


【解决方案1】:

你有密钥,你可以使用get获取与密钥关联的值,现在你要做的就是创建一个Map.Entry,我们可以使用Map.entry工厂方法来做到这一点:

var value = theBackingLinkedHashMap.get(key);
if (value == null) {
    return null;
}
return Map.entry(key, value);

entry 返回的条目确实有两个您应该注意的警告:

  • 不允许空键,因此您的NavigableLinkedHashMap 也需要不允许空键
  • 是不可变的,因此您不能调用setValue

但除此之外,它就像你从支持LinkedHashMap 中获得了Map.Entry 一样,它确实履行了ceilingEntryfloorEntry 等的合同,因为他们只是要求一个“一个键值映射”,并且不需要它必须具有映射本身的可变性或类似的东西。例如,这是ceilingEntry

返回与大于或等于给定键的最小键关联的键值映射,如果没有这样的键,则返回 null。

【讨论】:

  • 第二个是我对这种方法的主要关注。如果有人正在迭代entrySet() 并在条目上使用setValue(),我希望它能够更新Map
  • @TrippKinetics 对于entrySet 和其他Map 方法,您可以委托给LinkedHashMap 实现,不是吗?您只需要在ceilingEntryfloorEntry 等方法中创建自己的条目。整个想法是,与entrySet 不同,需要在ceilingEntryfloorEntry 等方法上调用setValue 的情况要少得多,因此尽管如此,这种实现仍然可以满足大量用例这个的。
【解决方案2】:

你可以做这样的事情。

Map<String,Integer> map = Map.of("Foo", 123, "Bar", 234);

Function<String, Entry<String,Integer>> getEntry = 
             getEntryFnc(map);
        
System.out.println(getEntry.apply("Foo"));
System.out.println(getEntry.apply("Bar"));
System.out.println(getEntry.apply("Baz"));

印刷

Foo=123
Bar=234
Baz=null    

返回一个 lambda,它使用提供的键和映射构建一个条目。

public static <K,V> Function<K, Entry<K,V>> getEntryFnc(Map<K,V> map) {
    return key-> 
           new AbstractMap.SimpleEntry<>(key, map.get(key));
    };
}

【讨论】:

  • 问题在于更新新的Entry 不会更新Map
【解决方案3】:

我会使用 TreeSet 将键保留在 NavigableMap 类中。请参见下面的示例:

import java.util.*;
public class Main{
    public static void main(String[] args) {
        NavMap<Integer, String> map = new NavMap<>();
        map.put(1, "one");
        map.put(2, "two");
        map.put(3, "three");
        map.put(4, "four");
        map.put(10, "ten");
        System.out.println(map.lowerKey(3));    //2
        System.out.println(map.higherKey(3));   //4
        System.out.println(map.higherEntry(3));  // 4:four
        System.out.println(map.ceilingKey(7));  //10
        System.out.println(map.floorKey(7));    //4
        System.out.println(map.floorEntry(10)); // 4:four
        
    }
}

class NavMap<K extends Comparable,V extends Comparable> extends LinkedHashMap<K,V>{
   private TreeSet<K> keys    = new TreeSet<>();
   
   public Set<K> keySet(){ return keys; }
   
   public K lowerKey  (K k){ return keys.lower(k);  }
   public K higherKey (K k){ return keys.higher(k); }
   public K floorKey  (K k){ return keys.floor(k);  }
   public K ceilingKey(K k){ return keys.ceiling(k);}
   
   public Map.Entry<K,V> lowerEntry(K k)   { return newEntry(lowerKey(k),  get(lowerKey(k)));}
   public Map.Entry<K,V> higherEntry(K k)  { return newEntry(higherKey(k), get(higherKey(k)));}
   public Map.Entry<K,V> floorEntry(K k)   { return newEntry(floorKey(k),  get(floorKey(k)));}
   public Map.Entry<K,V> ceilingEntry(K k) { return newEntry(ceilingKey(k),get(ceilingKey(k)));}
   private Map.Entry<K,V> newEntry(K k, V v) { return new AbstractMap.SimpleEntry<>(k,v);} 
   
   public V put(K key, V value){
      keys.add(key);
      return super.put(key, value);
   }
}

输出:

2
4
4=four
10
4
10=ten

【讨论】:

  • 我刚刚意识到 Map.keySet() 可能返回一个 TreeSet。在这种情况下,您不需要在 NavigableMap 中保留另一个 TreetSet 键。
  • 其实,上面的评论是错误的。 LinkedHashMap.keySet() 返回 LinkedHashMap.LinkedKeySet。
  • 这是行不通的,因为TreeSet 不会将密钥与LinkedHashSet 保持相同的顺序。
  • 不过,这给了我一个想法。而不是仅仅继承LinkedHashMap,也许我也应该继承LinkedHashSet。注释?
  • @TrippKinetics 我更新了代码。检查它是否都在那里。
猜你喜欢
  • 2021-06-05
  • 2013-04-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多