Java 基于密钥列表获取子哈希映射的最佳方法是什么?

Java 基于密钥列表获取子哈希映射的最佳方法是什么?,java,hashmap,Java,Hashmap,我有一个HashMap,我想得到一个新的HashMap,它只包含第一个HashMap中的元素,其中K属于一个特定的列表 我可以查看所有的键并填充一个新的HashMap,但我想知道是否有更有效的方法 谢谢如果您的钥匙有订购单,您可以使用树形图 查看TreeMap.subMap() 不过,它不允许您使用列表来执行此操作。根据您的使用情况,这可能是一种更有效的实现 public class MapView implements Map{ List ak; Map map; public M

我有一个HashMap,我想得到一个新的HashMap,它只包含第一个HashMap中的元素,其中K属于一个特定的列表

我可以查看所有的键并填充一个新的HashMap,但我想知道是否有更有效的方法


谢谢

如果您的钥匙有订购单,您可以使用树形图

查看
TreeMap.subMap()


不过,它不允许您使用列表来执行此操作。

根据您的使用情况,这可能是一种更有效的实现

public class MapView implements Map{
  List ak;
  Map map;
  public MapView(Map map, List allowableKeys) {
     ak = allowableKeys;
     map = map;
  }
  public Object get(Object key) {
    if (!ak.contains(key)) return null;
    return map.get(key);
  }
}

是的,有一个解决方案:

Map<K,V> myMap = ...;
List<K> keysToRetain = ...;
myMap.keySet().retainAll(keysToRetain);
Map myMap=。。。;
列表keysteretain=。。。;
myMap.keySet().retainal(keysToRetain);
Set
上的
retainAll
操作更新基础映射。看

编辑
请注意,此解决方案可修改
地图

复制地图并删除列表中未包含的所有键:

Map map2 = new Hashmap(map);
map2.keySet().retainAll(keysToKeep);
keys.stream()
    .filter(map::containsKey)
    .collect(Collectors.toMap(Function.identity(), map::get));

如果您有Map m1和List键,请尝试以下操作

Map m2 = new HashMap(m1);
m2.keySet().retainAll(keys);

您可以在列表上循环检查HashMap是否包含映射,而不是查看所有键。然后使用筛选的条目创建一个新的HashMap:

List<String> keys = Arrays.asList('a', 'c', 'e');

Map<String, String> old = new HashMap<>();
old.put('a', 'aa');
old.put('b', 'bb');
old.put('c', 'cc');
old.put('d', 'dd');
old.put('e', 'ee');

// only use an inital capacity of keys.size() if you won't add
// additional entries to the map; anyways it's more of a micro optimization
Map<String, String> newMap = new HashMap<>(keys.size(), 1f);

for (String key: keys) {
    String value = old.get(key);
    if (value != null) newMap.put(key, value);
}
List key=Arrays.asList('a','c','e');
Map old=新HashMap();
old.put('a','aa');
old.put('b','bb');
old.put('c','cc');
old.put('d','dd');
old.put('e','ee');
//如果不添加,请仅使用keys.size()的初始容量
//地图上的其他条目;无论如何,这更多的是一个微观优化
Map newMap=newhashmap(keys.size(),1f);
用于(字符串键:键){
字符串值=old.get(键);
if(value!=null)newMap.put(key,value);
}
您可以对返回的K HashMap使用clone()方法

大概是这样的:

import java.util.HashMap;

public class MyClone {    
     public static void main(String a[]) {    
        Map<String, HashMap<String, String>> hashMap = new HashMap<String, HashMap<String, String>>();    
        Map hashMapCloned = new HashMap<String, String>();    

        Map<String, String> insert = new HashMap<String, String>();

        insert.put("foo", "bar");
        hashMap.put("first", insert);

        hashMapCloned.put((HashMap<String, String>) hashMap.get("first").clone());

    }    
}
import java.util.HashMap;
公共类MyClone{
公共静态void main(字符串a[]){
Map hashMap=新hashMap();
Map hashMapCloned=新建HashMap();
Map insert=newhashmap();
插入。放入(“foo”、“bar”);
hashMap.put(“第一个”,插入);
hashMapClone.put((HashMap)HashMap.get(“first”).clone();
}    
}

它可能有一些语法错误,因为我还没有测试,但请尝试类似的方法。

否,因为HashMap没有维护其条目的顺序。如果需要某个范围之间的子贴图,可以使用TreeMap。还有,请看这个;它似乎与你的情况类似。

在番石榴的帮助下

假设您有一个映射
map
,并希望使用
List
List中的值进行子映射

Map<String, String> map = new HashMap<>();
map.put("1", "1");
map.put("2", "2");
map.put("3", "4");

final List<String> list = Arrays.asList("2", "4");

Map<String, String> subMap = Maps.filterValues(
                map, Predicates.in(list));
Map Map=newhashmap();
地图放置(“1”、“1”);
地图放置(“2”、“2”);
地图放置(“3”、“4”);
最终列表=Arrays.asList(“2”、“4”);
Map subMap=Maps.filterValues(
map,谓词。in(list));
更新/注意:正如注释中提到的@assylas,当使用
contains()
时,您将有O(n)。所以,如果您有一个大列表,这可能会对性能产生巨大影响


另一方面,
HashSet.contains()
是常数时间O(1),因此,如果有可能使用Set而不是List,这可能是一种很好的方法(请注意,将List转换为Set将花费O(n),因此最好不要转换:)

您要求的是一个新的
HashMap
。由于
HashMap
不支持结构共享,因此没有比显而易见的方法更好的方法了。(我在这里假设
null
不能是值)

新的
Map
get
方法如下

@Override
public V get(Object k) {
    if (!restrictedSetOfKeys.contains(k))
        return null;
    return originalMap.get(k);
}

请注意,如果
restrictedSetOfKeys
Set
而不是
List
则更好,因为如果它是
HashSet
,则
get
方法的时间复杂度通常为O(1)。

您甚至可以增加自己的时间复杂度:

public class FilteredMap<K, V> extends AbstractMap<K, V> implements Map<K, V> {

    // The map I wrap.
    private final Map<K, V> map;
    // The filter.
    private final Set<K> filter;

    public FilteredMap(Map<K, V> map, Set<K> filter) {
        this.map = map;
        this.filter = filter;
    }

    @Override
    public Set<Entry<K, V>> entrySet() {
        // Make a new one to break the bond with the underlying map.
        Set<Entry<K, V>> entries = new HashSet<>(map.entrySet());
        Set<Entry<K, V>> remove = new HashSet<>();
        for (Entry<K, V> entry : entries) {
            if (!filter.contains(entry.getKey())) {
                remove.add(entry);
            }
        }
        entries.removeAll(remove);
        return entries;
    }

}

public void test() {
    Map<String, String> map = new HashMap<>();
    map.put("1", "One");
    map.put("2", "Two");
    map.put("3", "Three");
    Set<String> filter = new HashSet<>();
    filter.add("1");
    filter.add("2");
    Map<String, String> filtered = new FilteredMap<>(map, filter);
    System.out.println(filtered);

}

对于Java8流,有一个功能(优雅)的解决方案。如果
keys
是要保留的密钥列表,
map
是源
map

keys.stream()
    .filter(map::containsKey)
    .collect(Collectors.toMap(Function.identity(), map::get));
完整示例:

    List<Integer> keys = new ArrayList<>();
    keys.add(2);
    keys.add(3);
    keys.add(42); // this key is not in the map

    Map<Integer, String> map = new HashMap<>();
    map.put(1, "foo");
    map.put(2, "bar");
    map.put(3, "fizz");
    map.put(4, "buz");

    Map<Integer, String> res = keys.stream()
        .filter(map::containsKey)
        .collect(Collectors.toMap(Function.identity(), map::get));

    System.out.println(res.toString());
List key=new ArrayList();
增加(2);
增加(3);
添加(42);//这把钥匙不在地图上
Map Map=newhashmap();
图.put(1,“foo”);
图.put(2,“bar”);
地图放置(3,“嘶嘶声”);
图.put(4,“buz”);
Map res=keys.stream()
.filter(映射::containsKey)
.collect(Collectors.toMap(Function.identity(),map::get));
System.out.println(res.toString());
打印:
{2=bar,3=fizz}


编辑为映射中缺少的键添加一个
过滤器

如果使用新映射而不是视图,则ak.contains
是O(n)vs O(1)-这可能是一个问题。结果映射视图不是哈希映射,甚至不是映射。@OP还指定了哈希映射。您所说的是一个树。您不能将
new
用作变量名。@Bubletan您是正确的,将变量重命名为newMap。@helper您应该使用
newhashmap(key.size(),1f)的方法
,否则将使用0.75的加载fatcor,并且一旦
ìf(value!=null)
不是HashMap的
containsKey
的有效替代品,则可以调整映射的大小。你可以编写
hashMap.put(“key”,null)
,然后你的
if(value!=null)
测试就会被愚弄。(当然,在这一点上,这是一个如此频繁的设计,以至于在映射中设置null值在一开始似乎是一个坏主意)在某些情况下,您可能希望在HashMap中存储null值(您仍然可以验证它是否包含用于消除带有null的映射或该特定键没有值之间歧义的键)。。。例如,当您使用它来缓存计算机密集型函数的结果时(结果可能为null)。。。所以这是行不通的。我更喜欢使用超类型/接口来声明变量,而不是具体的类。但他要求提供一个新的
HashMap
@KrishPrabakar,所以只需通过将原始映射传递给const来复制它
keys.stream()
    .filter(map::containsKey)
    .collect(Collectors.toMap(Function.identity(), map::get));
    List<Integer> keys = new ArrayList<>();
    keys.add(2);
    keys.add(3);
    keys.add(42); // this key is not in the map

    Map<Integer, String> map = new HashMap<>();
    map.put(1, "foo");
    map.put(2, "bar");
    map.put(3, "fizz");
    map.put(4, "buz");

    Map<Integer, String> res = keys.stream()
        .filter(map::containsKey)
        .collect(Collectors.toMap(Function.identity(), map::get));

    System.out.println(res.toString());