将类型为Object的ArrayList转换为另一个类型为Object的ArrayList的Java操作

3

我有一个带有成员变量的类:

class Filter{
  private String key;
  private String operator;
  private Object value;
}

以下是类型过滤器列表:

[
{
  key: status,
  operator:equal,
  value: active
},
{
  key: status,
  operator:equal,
  value: inactive
},
{
  key: name,
  operator:equal,
  value: jhon
},
{
  key: id,
  operator:equal,
  value: 123
}
] 

我想将上述的List转换为下面的新List,其中如果键相同key: status,则在新列表中只需要一个条目,其值为列表类型value: [active, inactive],操作符为IN
[
{
  key: status,
  operator:in,
  value: [active, inactive]
},
{
  key: name,
  operator:equal,
  value: jhon
},
{
  key: id,
  operator:equal,
  value: 123
}
]
 

如何最好、最有效地实现这个解决方案,最好使用Java 8流和Lambda?希望避免传统的for循环。

2个回答

3
你可以使用Collectors.partitioningBy根据过滤器的键是否为"status"List分成两部分。示例
final Map<Boolean, List<Filter>> parts = list.stream()
        .collect(Collectors.partitioningBy(f -> "status".equals(f.getKey())));
final Object[] statuses = parts.get(true).stream().map(Filter::getValue).toArray();
final List<Filter> result = parts.get(false);
if (statuses.length != 0) {
    result.add(0, new Filter("status", "in", statuses));
}

对于多个键,您可以使用Collectors.groupingBy

演示
final Map<String, List<Filter>> map = list.stream().collect(Collectors.groupingBy(Filter::getKey, LinkedHashMap::new, Collectors.toList()));
final List<Filter> result = map.entrySet().stream()
        .map(e -> e.getValue().size() > 1
                ? new Filter(e.getKey(), "in", e.getValue().stream().map(Filter::getValue).toArray())
                : e.getValue().get(0))
        .collect(Collectors.toList());

感谢@hev1的快速回复和建议,状态是一个例子,但还有许多其他类似于状态的关键字,它们将具有不同的值。例如,关键字“部门”,值:“dept1”和关键字:“部门”,值:dept2,因此我可能不知道哪些相同的关键字具有不同的值。 - Manoj Kumar
谢谢@hev1,我认为我必须将value成员的类型更改为List<Object>而不是Object。因为即使进行转换后,我仍然无法检索值。例如 - result [Filter [key = status,operator = in,value = [Ljava.lang.Object; @ 1c80dae9],Filter [key = name,operator = equal,value = abc]]。如果我的理解有误,请纠正我。 - Manoj Kumar
@ManojKumar,你尝试过我提供的演示吗?仍然可以检索结果。 - Unmitigated
@ManojKumar 请尝试这段代码:https://pastebin.com/RXW9y3As - Unmitigated
非常感谢 @hev1。现在我可以看到样例了。 - Manoj Kumar

2

首先,创建一个包含value列表的响应类。

class FilterRes{
  private String key;
  private String operator;
  private List<Object> values;
  // getter setter constractor
}

现在首先使用map()Filter转换为FilterRes,然后使用Collectors.toMap收集为映射,并在合并函数中合并组。然后在一个ArrayList中获取值。

Map<Integer, FilterRes> resMap = list.stream()
                .map(s -> new FilterRes(s.getKey(), s.getOperator(),
                                        new ArrayList<>(Arrays.asList(s.getValue()))))
                .collect(Collectors.toMap(FilterRes::getKey, e -> e,    
                                    (a, b) -> new FilterRes(a.getKey(), "in", 
                                                Stream.concat(a.getValue().stream(),
                                                              b.getValue().stream())
                                                         .collect(Collectors.toList()))));

List<FilterRes> resList= new ArrayList(resMap.values()); // Create list from map values

谢谢 @用户 - 点赞不要说谢谢。你是如何处理操作变量使其变为“IN”而不是“equal”的? - Manoj Kumar
非常感谢 @User - 点赞不要说谢谢,这对我真的非常有帮助。 - Manoj Kumar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接