Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/ssh/2.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
Java 从数组中收集键值以进行映射,无重复项_Java - Fatal编程技术网

Java 从数组中收集键值以进行映射,无重复项

Java 从数组中收集键值以进行映射,无重复项,java,Java,我的应用程序从web服务获取一些字符串。看起来是这样的: name=Raul&city=Paris&id=167136 name=Raul&city=Paris&id=167136&city=Oslo 我想从以下字符串获取地图: {name=Raul, city=Paris, id=167136} 代码: 这在大多数情况下都可以正常工作,但应用程序可以获得具有重复键的字符串,如下所示: name=Raul&city=Paris&i

我的应用程序从web服务获取一些字符串。看起来是这样的:

name=Raul&city=Paris&id=167136

name=Raul&city=Paris&id=167136&city=Oslo
我想从以下字符串获取地图:

{name=Raul, city=Paris, id=167136}

代码:

这在大多数情况下都可以正常工作,但应用程序可以获得具有重复键的字符串,如下所示:

name=Raul&city=Paris&id=167136

name=Raul&city=Paris&id=167136&city=Oslo
应用程序将崩溃,出现以下未捕获的异常:

Exception in thread "main" java.lang.IllegalStateException: Duplicate key city (attempted merging values Paris and Oslo)
我尝试更改收集方法:

但编者说没有:

Cannot resolve method 'collect(java.util.stream.Collector<T,capture<?>,java.util.Map<K,U>>, <lambda expression>)'

无法解析方法“collect(java.util.stream.Collector)”您误解了
toMap
(合并运算符)的最后一个参数。当它找到一个重复的键时,它会将映射中的当前值和具有相同键的新值交给合并运算符,该运算符生成要存储的单个值


例如,如果您只想存储找到的第一个值,然后使用
(s1,s2)->s1
。如果您想用逗号分隔它们,请使用
(s1,s2)->s1+,“+s2

,使用kotlin
集合可以获得相同的结果

val res = message
        .split("&")
        .map {
            val entry = it.split("=")
            Pair(entry[0], entry[1])
        }
println(res)
println(res.toMap()) //distinct by key
结果是

[(姓名,劳尔),(巴黎市),(id,167136),(奥斯陆市)]


{name=Raul,city=Oslo,id=167136}

如果您想将重复键的值添加到一起并按键对它们进行分组(因为应用程序可以获得包含重复键的字符串),而不是使用
collector.toMap()
您可以将
收集器.groupingBy
与自定义收集器(
collector.of(…)
):


为什么不使用库来解析查询字符串呢?手工解析是一个非常糟糕的主意,因为有上百种情况下,您的代码会丢失!例如,标志(没有值的属性)呢或者URL编码的数据?在特定情况下,只需为收集器使用自定义合并策略即可。TL;DR:不,在大多数情况下,它不起作用。正在修复此特定解析问题,但会留下大量其他问题。解析查询的库是什么?你能提供一个好的示例吗?这是否回答了你的问题?(请注意,逗号分隔建议会受到字符串concat in-loop反模式的影响),而字符串concat in-loop反模式会受到置换优化反模式的影响:-)在这一点上我不同意。我认为引用经常被误用——我确信这里就是这样。特别是因为有一个加入收集器专门解决这个常见问题。我同意在这种情况下,使用一个
groupingBy
和一个下游
加入
收集器将更有意义。但是我不同意string-concat-in-loop通常是一种反模式。多年来,我看到很多愚蠢的代码使用
StringBuilder
来提高理论性能,但没有证据表明在这种特定情况下需要它——但有很多证据表明它使代码的可读性大大降低。很明显,我支持你,这是正确的答案。我们在争论抽象理论——我完全同意人们可以用代码做愚蠢的事情,不管工具有多大的帮助。这个问题被标记为Java。为什么不使用带有重复键函数的映射收集器?其目的不是更明显吗?@Boristespider我更喜欢
Set
,而不是c一个字符串,如
s1+,”+s2
,毕竟这取决于问题作者的需要!是的,但在任何情况下都不需要您建议的自定义收集器。作者特别要求只取一个值-这可以通过自定义合并函数轻松解决。我没有说这是必需的,或者这是唯一的解决方案,它可以为其他人服务r愿意有这种行为而不是有单一价值观的人
String input = "name=Raul&city=Paris&city=Berlin&id=167136&id=03&id=505";

Map<String, Set<Object>> result = Arrays.stream(input.split("&"))
                .map(splitedString -> splitedString.split("="))
                .filter(keyValuePair -> keyValuePair.length() == 2)
                .collect(
                        Collectors.groupingBy(array -> array[0], Collector.of(
                                () -> new HashSet<>(), (set, array) -> set.add(array[1]),
                                (left, right) -> {
                                    if (left.size() < right.size()) {
                                        right.addAll(left);
                                        return right;
                                    } else {
                                        left.addAll(right);
                                        return left;
                                    }
                                }, Collector.Characteristics.UNORDERED)
                        )
                );
result => size = 3
 "city" -> size = 2 ["Berlin", "Paris"]
 "name" -> size = 1 ["Raul"]
 "id"   -> size = 3 ["167136","03","505"]