java - Java Streams - 根据列表的值组成一个值
问题描述
使用 Java 8 并使用 Streams 处理某些对象的列表,我需要根据其他值的属性为列表的每个值分配一个属性。
想象一下具有以下属性的 Java MyClass 中的类:
String value1;
String value2;
LocalDate theDate;
String uniqueId;
想象一下 MyClass 对象的列表,就像:
List<MyClass> myList = new ArrayList<>();
uniqueId
在本练习开始时,该属性是空的。
映射列表后,uniqueId
必须按照以下策略设置:
<value1>-<value2>-N
其中N
是<value1>-<value2>
按 排序的组合出现的次数theDate
。
鉴于 JSON 中给出的这个示例:
[
{"value1":"1111111", "value2":"A", "theDate": "2020-06-01", "uniqueId": null},
{"value1":"1111111", "value2":"A", "theDate": "2020-06-02", "uniqueId": null},
{"value1":"1111111", "value2":"A", "theDate": "2020-06-03", "uniqueId": null},
{"value1":"1111111", "value2":"A", "theDate": "2020-06-04", "uniqueId": null},
{"value1":"1111111", "value2":"B", "theDate": "2020-06-01", "uniqueId": null},
{"value1":"1111111", "value2":"B", "theDate": "2020-06-02", "uniqueId": null},
{"value1":"1111111", "value2":"B", "theDate": "2020-06-03", "uniqueId": null}
]
执行后应导致:
[
{"value1":"1111111", "value2":"A", "theDate": "2020-06-01", "uniqueId": "1111111-A-1"},
{"value1":"1111111", "value2":"A", "theDate": "2020-06-02", "uniqueId": "1111111-A-2"},
{"value1":"1111111", "value2":"A", "theDate": "2020-06-03", "uniqueId": "1111111-A-3"},
{"value1":"1111111", "value2":"A", "theDate": "2020-06-04", "uniqueId": "1111111-A-4"},
{"value1":"1111111", "value2":"B", "theDate": "2020-06-01", "uniqueId": "1111111-B-1"},
{"value1":"1111111", "value2":"B", "theDate": "2020-06-02", "uniqueId": "1111111-B-2"},
{"value1":"1111111", "value2":"B", "theDate": "2020-06-03", "uniqueId": "1111111-B-3"}
]
我显然可以使用传统的循环策略来做到这一点。但问题是,使用 Streams,我如何设法跟踪列表的其余值,以便我可以组成我的组合值?还是不能使用 Streams?
myList.stream()
.map(o -> {
// How do I make here to keep the track of the rest of the values of the list?
})
.collect(Collectors.toList());
谢谢你。
解决方案
这不是真正的东西是流闪耀,这有两个原因。首先是您正在MyClass
通过副作用操作对象(当然,这是可以避免的),并且因为 Java 缺乏对mapWithIndex
or之类的开箱即用的支持zipWithIndex
,这在这里非常有帮助。您可以在此处找到有关如何解决该特定问题的更多信息。
无论如何,可以通过流进行。
首先,我定义了这个辅助方法:
public static MyClass setUniqueId(MyClass myClass, int i) {
myClass.uniqueId = String.format("%s-%s-%s", myClass.value1, myClass.value2, i);
return myClass;
}
它应该是相当不言自明的 - 它使用提供的 int 设置唯一 id 并返回对象本身,现在使用 id 集。
value1
然后,通过按相等和value2
值对流中的元素进行分组,可以做你想做的事。对元素进行分组后,我们可以通过使用它们的索引进行压缩来设置它们的唯一 ID。由于 Java 缺乏对此的支持,我们需要通过使用IntStream
带有我们用来从中获取索引的范围的范围来以一种倒退的方式来做到这一点。把它们放在一起,我们得到这个:
list.stream()
.collect(Collectors.groupingBy(obj -> obj.value1 + "-" + obj.value2))
.forEach((klass, values) -> {
IntStream.range(0, values.size())
.forEach(i -> setUniqueId(values.get(i), i));
});
另一种可能更清晰的方法是对分组结果进行 flatMap:
var results = list.stream()
.collect(Collectors.groupingBy(obj -> obj.value1 + "-" + obj.value2))
.values().stream()
.flatMap(values ->
IntStream.range(0, values.size())
.mapToObj(i -> setUniqueId(values.get(i), i)))
.sorted((a, b) -> a.date.compareTo(b.date))
.collect(Collectors.toList());
推荐阅读
- django - 如何在 django 的文本内容中使用循环值
- firefox - Firefox 开发工具绘制闪烁视图:不同颜色代表什么?
- r - 对于 R 数据框中的一列,即使一个值不是 NA,然后用该值替换所有 NA?
- android - Google VR 示例构建失败并出现空指针异常
- php - 如何防止ajax运行同一个php文件的多个实例?
- php - 获取未定义的索引:甚至定义了索引
- xml - 使用 XSLT 计算嵌套子元素的数量
- dialogflow-es - 如何让 Dialogflow 接受所需实体的任何输入
- dynamics-crm - 为什么我无法注册我的 CRM 自定义工作流活动?
- database - 使用快照备份 Cassandra 集群并上传到 s3/vm?