Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/386.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
以Java8函数式向现有键添加非重复元素_Java_Lambda_Hashmap - Fatal编程技术网

以Java8函数式向现有键添加非重复元素

以Java8函数式向现有键添加非重复元素,java,lambda,hashmap,Java,Lambda,Hashmap,我有一张要填充的地图: private Map<String, Set<String>> myMap = new HashMap<>(); compute()调用如下: for (String line : messages) { String[] parts = line.split("-"); validator.validate(parts); //validates parts are as expected String

我有一张要填充的地图:

private Map<String, Set<String>> myMap = new HashMap<>(); 
compute()
调用如下:

for (String line : messages) {
    String[] parts = line.split("-");
    validator.validate(parts); //validates parts are as expected
    String key = parts[parts.length - 1];

    compute(key, parts);
}
零件
元素如下:

[AB, CC, 123]
[AB, FF, 123]
[AB, 456]
compute()

我的问题是:如何使用Java8函数样式(例如

{123=[AB, FF, CC]}

根据您的要求,我添加了一个lambda变体,它只是通过lambda将零件添加到
compute
-方法中的映射中:

private void compute(String key, String[] parts) {
  myMap.computeIfAbsent(key, 
    s -> Stream.of(parts)
               .limit(parts.length - 1)
               .collect(toSet()));
}
但在这种情况下,您只能在地图中获得类似
123=[AB,CC]
的内容。如果还想添加后续调用中出现的所有值,请使用
merge

private void compute(String key, String[] parts) {
  myMap.merge(key, 
    s -> Stream.of(parts)
               .limit(parts.length - 1)
               .collect(toSet()),
               (currentSet, newSet) -> {currentSet.addAll(newSet); return currentSet;});
}
我不确定您对
computeIfAbsent
的意图,但从您列出的
部分和您期望的输出来看,您可能还想尝试以下内容,而不是列出的全部代码:

// the function to identify your key
Function<String[], String> keyFunction = strings -> strings[strings.length - 1];
// the function to identify your values
Function<String[], List<String>> valuesFunction = strings -> Arrays.asList(strings).subList(0, strings.length - 1);
// a collector to add all entries of a collection to a (sorted) TreeSet 
Collector<List<String>, TreeSet<Object>, TreeSet<Object>> listTreeSetCollector = Collector.of(TreeSet::new, TreeSet::addAll, (left, right) -> {
  left.addAll(right);
  return left;
});

Map myMap = Arrays.stream(messages) // or: messages.stream()
  .map(s -> s.split("-"))
  .peek(validator::validate)
  .collect(Collectors.groupingBy(keyFunction,
      Collectors.mapping(valuesFunction, listTreeSetCollector)));
生成包含以下内容的地图:

123=[AB, CC, FF]
456=[AB]

最后,但并非最不重要:如果可以,将键和值本身传递给方法。不要分裂关于识别键和识别值的逻辑。这使得以后或其他人很难理解您的代码。

要向可能存在的密钥添加更多部分,您使用了错误的方法;您想要的是
merge()
,而不是
computeIfAbsent()

如果
validator.valudate()
抛出选中的异常,则必须在流外部调用它,因此需要一个foreach循环:

for (String message : messages) {
    String[] parts = message.split("-");
    validator.validate(parts);
    LinkedList<String> list = new LinkedList(Arrays.asList(parts));
    String key = list.getLast();
    list.removeLast();
    myMap.merge(key, new HashSet<>(list), Set::addAll);
}
for(字符串消息:消息){
String[]parts=message.split(“-”);
验证程序。验证(部件);
LinkedList=新的LinkedList(Arrays.asList(parts));
String key=list.getLast();
list.removeLast();
merge(key,newhashset(list),Set::addAll);
}
使用具有方法
getLast()
removeLast()
LinkedList
,可以使代码非常可读

免责声明:代码可能无法编译或工作,因为它是在我的手机上登录的(但有一个合理的机会它会工作)

尝试以下方法:

private void compute(String[] parts) {
    int lastIndex = parts.length - 1;
    String key = parts[lastIndex];
    List<String> values = Arrays.asList(parts).subList(0, lastIndex);
    myMap.computeIfAbsent(key, k -> new HashSet<>()).addAll(values);
}
private void compute(字符串[]部分){
int lastIndex=parts.length-1;
字符串键=零件[lastIndex];
列表值=数组.asList(parts).subList(0,lastIndex);
myMap.computeIfAbsent(key,k->newhashset()).addAll(value);
}
或者,如果需要,可以使用流替换整个循环:

Map<String, Set<String>> myMap = messages.stream()     // if messages is an array, use Arrays.stream(messages)
        .map(line -> line.split("-"))
        .peek(validator::validate)
        .collect(Collectors.toMap(
                parts -> parts[parts.length - 1],
                parts -> new HashSet<>(Arrays.asList(parts).subList(0, parts.length - 1)),
                (a, b) -> { a.addAll(b); return a; }));
Map myMap=messages.stream()//如果消息是数组,请使用Arrays.stream(消息)
.map(直线->直线分割(“-”)
.peek(验证器::验证)
.collect(collector.toMap)(
零件->零件[parts.length-1],
parts->newhashset(Arrays.asList(parts).subList(0,parts.length-1)),
(a,b)->{a.addAll(b);返回a;});

我想你使用的是
地图
,对吧?如果是这样,为什么不改用
映射
映射
呢?只有在数组中不存在与现有键相关联的值时,才想将该值添加到数组中,对吗?@Thomas edited post添加映射信息。map是
map
@dabadaba向
集合添加值
如果存在则与键关联,如果不存在则添加新键并填充。请查看
computeifassent
上的JavaDoc示例:
map.computeifassent(key,k->new HashSet()).add(v)并对其进行调整-如果不存在,您将创建一个新集合,否则将添加一个新值。然后只需添加除最后一个之外的所有数组元素,例如,通过将这些元素转换为列表并调用
addAll(list)
。当我首先拆分
String[]parts=line.split(“-”)时,您是否可以更改答案以删除
拆分
;有效。验证(部分)部分
传递给包含答案主体的方法(重新表述的注释)之前,请执行code>;在调用
getMessage(parts)
之后,是否要在映射中拥有所有可能值的完整列表?如果是这样,我不能推荐它。我不再使用
getMessage(parts
。一旦
parts
拆分后被构造,那么
parts
就被验证了。从那以后,我的意图是将
parts
传递给
计算(parts)
它应该用对应键的唯一值填充映射。我的假设是正确的,消息数组包含以下内容:
新字符串[]{“AB-CC-123”、“AB-FF-123”、“AB-456”};
?如果是这样,只要使用
computeFabSent
(除非你做了不可取的事情;-)。我添加了两个变体(1个用于ComputeFabSent,1个用于merge)通过lambda表达式添加<代码>部件。在完整的计算变量中添加验证。如果不进行昂贵的计算或验证,您可能还需要考虑预先完成完整的计算(如第一示例所示)。<代码> SET::ADDALL);<代码>抱怨浮点不是功能接口。知道为什么会这样,应该用什么来代替它吗?如果
validate()
引发异常,又该怎么办?上述内容是否会改变?@user2781389缺少括号-答案已更新。现在试一试(免责声明仍然适用,因为我仍然只是在iPhone上翻拇指)。我假设validate会引发运行时异常。能否在方法ref中将答案更新为错误的返回类型?无法将布尔值转换为Set。另外,validate会抛出自定义异常,该异常扩展了异常,所以如何处理lambda?@user2781389若validate抛出一个选中的异常,那个么您就不能从流调用它——这是一个语言规则。我已经修改了代码以适应这种情况,结果还是可读性更好。`parts->parts[parts.length-1],`this not com
private void compute(String[] parts) {
    int lastIndex = parts.length - 1;
    String key = parts[lastIndex];
    List<String> values = Arrays.asList(parts).subList(0, lastIndex);
    myMap.computeIfAbsent(key, k -> new HashSet<>()).addAll(values);
}
Map<String, Set<String>> myMap = messages.stream()     // if messages is an array, use Arrays.stream(messages)
        .map(line -> line.split("-"))
        .peek(validator::validate)
        .collect(Collectors.toMap(
                parts -> parts[parts.length - 1],
                parts -> new HashSet<>(Arrays.asList(parts).subList(0, parts.length - 1)),
                (a, b) -> { a.addAll(b); return a; }));