按特定逻辑合并 ArrayList of Integers
Posted
技术标签:
【中文标题】按特定逻辑合并 ArrayList of Integers【英文标题】:Merge ArrayList of Integers by specific logic 【发布时间】:2019-05-05 21:33:18 【问题描述】:我的 ArrayList 包含我的简单模型类 User 的许多实例,其中仅包含 2 个字段:
@Data
public class User
private String email;
private ArrayList<Integer> lists;
我在 lists 字段中插入整数值,总是 1 或 0。 User 类有许多对象,其中一些是重复的,因为它们具有相同的 email 地址但不同的列表。
我需要将 Users 的重复项合并到 User 的一个对象中,同时还要注意 lists 字段。
User user1 = new User('email@gmail.com', Arrays.asList(0, 1, 0, 1, 1));
User user2 = new User('email@gmail.com', Arrays.asList(0, 0, 0, 1, 1));
User user3 = new User('email@gmail.com', Arrays.asList(1, 1, 1, 1, 1));
/* merge duplicated objects into one */
User mergedUser = new User('email@gmail.com', Arrays.asList(1, 1, 1, 1, 1));
我在实现将许多 列表 合并为一个的逻辑时遇到了困难。 其背后的逻辑并不复杂:只要有1,就将1放入合并列表。有许多具有 0 且只有一个 1 的列表,会在最终合并列表中产生值 1。
我应该采取什么方法来实现这个合并列表的逻辑?
【问题讨论】:
【参考方案1】:从JDK8开始,你可以使用toMap
方法来完成你的任务。
Collection<User> result =
list.stream()
.collect(toMap(User::getEmail,
Function.identity(),
(l, r) ->
List<Integer> firstList = l.getList();
List<Integer> secondList = r.getList();
IntStream.range(0, firstList.size())
.forEach(i -> firstList.set(i, Math.max(firstList.get(i), secondList.get(i))));
return l;
)).values();
您可以通过将合并逻辑提取到辅助方法中来进一步使其更具可读性:
private static User apply(User l, User r)
List<Integer> firstList = l.getList();
List<Integer> secondList = r.getList();
IntStream.range(0, firstList.size())
.forEach(i -> firstList.set(i, Math.max(firstList.get(i), secondList.get(i))));
return l;
那么你可以这样做:
Collection<User> result = list.stream()
.collect(toMap(User::getEmail, Function.identity(), Main::apply))
.values();
其中Main
指的是包含apply
方法的类。
注意这里重要的是合并函数 ((l, r) -> ...
),see this answer 稍微解释了合并函数。
您可能需要使用toMap
收集器来了解my other posts 以熟悉它和ofcourse the API doc。
【讨论】:
【参考方案2】:你可以这样做:
List<User> finalList = new ArrayList<>(users.stream()
.collect(Collectors.toMap(User::getEmail, Function.identity(), (user1, user2) ->
List<Integer> l1 = user1.getLists();
List<Integer> l2 = user2.getLists();
List<Integer> merge = IntStream.range(0, l1.size())
.mapToObj(i -> (l1.get(i) == 0 && l2.get(i) == 0) ? 0 : 1)
.collect(Collectors.toList());
return new User(user1.getEmail(), merge);
)).values());
【讨论】:
【参考方案3】:List的值总是0或者1,我推荐使用long或者long[]而不是ArrayList
@Data
@AllArgsConstructor
public class User
private String email;
private long flags;
public static long merge(long... flags)
long result = 0;
for (long flag : flags)
result = result | flag;
return result;
// test
public static void main(String[] args)
User user1 = new User("email@gmail.com", Long.valueOf("1000000000000101",2));
User user2 = new User("email@gmail.com", Long.valueOf("0000111100000101",2));
User user3 = new User("email@gmail.com", Long.valueOf("0000000010110101",2));
System.out.println(Long.toBinaryString(merge(user1.flags, user2.flags, user3.flags)));
// result is 1000111110110101
如果flags的数量大于32,使用long[]保存更多的flags;
【讨论】:
我无法理解这会给mergedUser
提供什么,如 OP 所示?
用户 mergeUser = new User("email@gmail.com", merge(user1.flags, user2.flags, user3.flags));以上是关于按特定逻辑合并 ArrayList of Integers的主要内容,如果未能解决你的问题,请参考以下文章