有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java合并特定逻辑的整数数组列表

我的ArrayList包含我的简单模型类的许多实例User,其中只包含两个字段:

@Data
public class User {
    private String email;
    private ArrayList<Integer> lists; 
}    

我在列表字段中插入整数值,总是10。 有许多用户类的对象,其中一些对象是重复的,因为它们具有相同的电子邮件地址,但不同的列表

我需要将用户的副本合并到用户的一个对象中,同时还要处理列表字段

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

我应该采取什么方法来实现合并列表的逻辑


共 (3) 个答案

  1. # 1 楼答案

    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
      }
    }
    

    如果标志数量大于32,则使用long[]保存更多标志

  2. # 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. # 3 楼答案

    从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方法的类


    注意,这里重要的是merge函数((l, r) -> { ...),see this answer,它解释了一点merge函数

    您可能希望使用toMap收集器来研究my other posts,以熟悉它和ofcourse the API doc