在Java8+;

在Java8+;,java,java-stream,Java,Java Stream,我有一张地图和一张列表。我想根据条件划分映射 foreach(map.key -> list.contains(map.key)) 并生成两张地图。最优雅的方式是什么?我使用的是Java11,所以您可以在答案中输入您想要的任何内容 我现在想到的是: map.entrySet() .stream() .collect(partitioningBy(e -> list.contains(o.getKey()))); 但是这会产生一个映射你不可能真正使用流生成两个单独的映射

我有一张
地图
和一张
列表
。我想根据条件划分
映射

foreach(map.key -> list.contains(map.key))
并生成两张地图。最优雅的方式是什么?我使用的是Java11,所以您可以在答案中输入您想要的任何内容

我现在想到的是:

map.entrySet()
   .stream()
   .collect(partitioningBy(e -> list.contains(o.getKey())));

但是这会产生一个
映射

你不可能真正使用流生成两个单独的映射(至少不是以最优雅的方式)。不要害怕使用旧的常规
forEach
,我认为它是一个相当干净的版本:

Map<String, String> contains = new HashMap<>();
Map<String, String> containsNot = new HashMap<>();

for(Map.Entry<String, String> entry : yourMap.entrySet()) {
    if (yourList.contains(entry.getKey())) {
        contains.put(entry.getKey(), entry.getValue());
    } else {
        containsNot.put(entry.getKey(), entry.getValue());
    }
}
Map contains=newhashmap();
Map containsNot=new HashMap();
for(Map.Entry:yourMap.entrySet()){
if(yourList.contains(entry.getKey())){
包含.put(entry.getKey(),entry.getValue());
}否则{
containsNot.put(entry.getKey(),entry.getValue());
}
}

您可以使用
toMap
减少每个组(作为下游收集器):

Map myMap=newhashmap();
myMap.put(“d”、“d”);
myMap.put(“c”、“c”);
myMap.put(“b”、“b”);
myMap.put(“A”、“A”);
List myList=Arrays.asList(“a”、“b”、“c”);
Map result=myMap.entrySet()
.stream()
.collect(收集器(
entry->myList.contains(entry.getKey()),
toMap(条目::getKey,条目::getValue)
)
);

对于这个例子,它产生
{false={A=A,d=d},true={b=b,c=c}}
您可以通过对原始
映射应用过滤来过滤
映射
,例如:

List<String> list = new ArrayList<>(); //List of values
Map<String, String> map = new HashMap<>();

Map<String, String> filteredMap = map.entrySet()
.stream()
.filter(e -> list.contains(e.getKey()))
.collect(Collectors.toMap(Entry::getKey, Entry::getValue));
List List=new ArrayList()//价值清单
Map Map=newhashmap();
Map filteredMap=Map.entrySet()
.stream()
.filter(e->list.contains(e.getKey()))
.collect(Collectors.toMap(条目::getKey,条目::getValue));

然后,您可以将
filteredMap
内容与原始
map
进行比较,以提取
filteredMap
中不存在的条目,作为@ernest_k答案的补充。您可以使用函数和
groupingBy

Map<String, String> myMap = new HashMap<>();
myMap.put("d", "D");
myMap.put("c", "C");
myMap.put("b", "B");
myMap.put("A", "A");
List<String> myList = Arrays.asList("a", "b", "c");

Function<Entry<String, String> , Boolean> myCondition =  i -> myList.contains(i.getKey());

Map<Boolean,List<Entry<String, String>>>  myPartedMap = myMap.entrySet()
        .stream().collect(Collectors.groupingBy(myCondition));

System.out.println(myPartedMap);
Map myMap=newhashmap();
myMap.put(“d”、“d”);
myMap.put(“c”、“c”);
myMap.put(“b”、“b”);
myMap.put(“A”、“A”);
List myList=Arrays.asList(“a”、“b”、“c”);
函数myCondition=i->myList.contains(i.getKey());
Map myPartedMap=myMap.entrySet()
.stream().collect(收集器.groupingBy(myCondition));
System.out.println(myPartedMap);

但是当您需要根据条件将两个备选方案作为输出时,可以使用
分区方式。然而,另一种解决方法(对于基于单个条件创建地图很有用)是使用
收集器

Map<String, String> myMap = Map.of("d", "D","c", "C","b", "B","A", "A");
List<String> myList = List.of("a", "b", "c");
Predicate<String> condition = myList::contains;

Map<String, String> keysPresentInList = myMap.keySet()
        .stream()
        .collect(Collectors.filtering(condition,
                Collectors.toMap(Function.identity(), myMap::get)));
Map<String, String> keysNotPresentInList = myMap.keySet()
        .stream()
        .collect(Collectors.filtering(Predicate.not(condition),
                Collectors.toMap(Function.identity(), myMap::get)));

您可以迭代映射并使用Java 8+中引入的优点:

Map<Boolean, Map<String, String>> result = Map.of(true, new LinkedHashMap<>(), 
                                                  false, new LinkedHashMap<>());
Set<String> set = new HashSet<>(list);
map.forEach((k, v) -> result.get(set.contains(k)).put(k, v));
Map result=Map.of(真,新LinkedHashMap(),
false,新建LinkedHashMap());
Set Set=新哈希集(列表);
map.forEach((k,v)->result.get(set.contains(k)).put(k,v));
首先,我们创建一个
result
映射,其中包含两个条目,每个分区一个条目。这些值是
LinkedHashMap
s,以便保留插入顺序

然后,我们从列表中创建一个
HashSet
,这样调用
set.contains(k)
就是一个
O(1)
操作(否则,如果我们做了
list.contains(k)
,那么对于映射的每个条目,这将是
O(n)
,从而产生总时间复杂度
O(n^2)
,这是不好的)


最后,根据调用
set的结果,我们迭代输入映射并将
(k,v)
条目放入相应的分区中。contains(k)

请阅读您能用实际数据给出一个您想要实现的示例吗?在这里我不必全速前进:一条流创建一个结果,但你想要两张地图?!请参阅相关stackoverflow.com/questions/28856781。最佳方法取决于地图和列表的大小,以及如何使用结果。例如,Guava Maps可以简单而快速地在原始地图上提供2个过滤视图,以避免额外的内存使用,但如果在结果中多次调用contains(),则可能会有非常糟糕的性能。我猜使用stream().filter(…).collect(…)也一样?@asoob确实如此。根据Darshan的回答,这种方法的性能很差O(n*m),当对于HashMaps和input,给定get()和contains()有O(1)时,O(m)的解决方案是可能的。见stackoverflow.com/questions/28856781
myMap.keySet().retainAll(myList);
Map<Boolean, Map<String, String>> result = Map.of(true, new LinkedHashMap<>(), 
                                                  false, new LinkedHashMap<>());
Set<String> set = new HashSet<>(list);
map.forEach((k, v) -> result.get(set.contains(k)).put(k, v));