Объединить ArrayList целых чисел по определенной логике - PullRequest
0 голосов
/ 04 декабря 2018

У меня есть ArrayList, содержащий много экземпляров моего простого класса моделей Пользователь , содержащий всего 2 поля:

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

Я вставляю в списки целочисленные значения полейвсегда 1 или 0 .Имея много объектов класса User , некоторые из них являются дубликатами, поскольку имеют одинаковый адрес email , но разные списки .

Мне нужно объединить дубликаты пользователей в один объект пользователя , также заботясь о поле списки .

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 ]

0 голосов
/ 04 декабря 2018

Вы можете сделать это так:

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());
0 голосов
/ 04 декабря 2018

Значение 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 [] для сохранениябольше флагов;

0 голосов
/ 04 декабря 2018

Начиная с 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) -> { ...), см. этот ответ , который немного объясняет функцию слияния.

Возможно, вы захотите посмотреть мои другие сообщения использование toMap коллекторов для ознакомления с ним и конечно API документ .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...