Объединить 2 списка на основе оригинального порядка из списка ввода - JAVA - PullRequest
1 голос
/ 27 февраля 2020

У меня есть следующая функция:

List<Pair<SomeObject, Integer>> process(List<SomeObject> input) {
   List<Pair<SomeObject, Integer>> result = new ArrayList<>();
   List<SomeObject> couldBeProcessed = new ArrayList<>();

   for (SomeObject obj : input) {
      if (couldBeProcessed(obj)) {
         couldBeProcessed.add(obj);
      } else {
         result.add(Pair.of(obj, 0));
      }
   }

   List<Pair<SomeObject, Integer>> processResult = processInBatch(couldBeProcessed); 
   // TODO: merge processResult with result here
}

Как мне добавить это processResult в results, но сохранить порядок, который был задан мне в input?

Ответы [ 2 ]

2 голосов
/ 27 февраля 2020

Как насчет использования карты для хранения индекса и затем хорошего значения для l oop:

List<Pair<SomeObject, Integer>> process(List<SomeObject> input) {
   List<Pair<SomeObject, Integer>> result = new ArrayList<>();
   Map<Integer, Pair<SomeObject, Integer>> map = new HashMap();
   List<SomeObject> couldBeProcessed = new ArrayList<>();

   for (int i = 0; i < input.size(); i++) {
      if (couldBeProcessed(input.get(i))) {
         couldBeProcessed.add(obj);
      } else {
         map.put(i, Pair.newInstance(obj, 0));
      }
   }

   List<Pair<SomeObject, Integer>> processResult = processInBatch(couldBeProcessed); 

   for (int i = 0; i < input.size(); i++) {
      if (map.containsKey(i)) {
         result.add(map.get(i));
      } else {
         result.add(processResult.remove(0));
      }
   }
}

Вы также можете использовать Map#computeIfAbsent, чтобы сделать второй л oop более компактно:

for (int i = 0; i < input.size(); i++) {
    result.add(map.computeIfAbsent(i, index -> processResult.remove(0));
}

PS: элементы processResult должны иметь те же индексы, что и соответствующие объекты из исходного списка.

@ Миша предлагает более естественный способ обрабатывать обработанную очередь - используя Deque:

Deque<Pair<SomeObject, Integer>> processResult = new ArrayDeque(processInBatch(couldBeProcessed)); 

for (int i = 0; i < input.size(); i++) {
    if (map.containsKey(i)) {
        result.add(map.get(i));
    } else {
        result.add(processResult.removeFirst());
    }
}
0 голосов
/ 27 февраля 2020

Множество предложений возможно при текущих встроенных реализациях:

List<Pair<SomeObject, Integer>> process(List<SomeObject> input) {

    // use an index map if the initial order matters
    Map<SomeObject, Integer> indexMap = IntStream.range(0, input.size())
            .boxed()
            .collect(Collectors.toMap(input::get, Function.identity()));

    // to split to either 'true' or 'false' you can use partitioning 
    Map<Boolean, List<SomeObject>> partitioned = input.stream()
            .collect(Collectors.partitioningBy(this::couldBeProcessed));

    List<Pair<SomeObject, Integer>> result = partitioned.get(Boolean.FALSE).stream()
            .map(some -> Pair.of(some, 0))
            .collect(Collectors.toList());

    List<SomeObject> couldBeProcessed = partitioned.get(Boolean.TRUE);

    List<Pair<SomeObject, Integer>> processResult = processInBatch(couldBeProcessed);

    // while merging use the index from initial phases
    return Stream.concat(processResult.stream(), result.stream())
            .sorted(Comparator.comparing(e -> indexMap.get(e.getLeft())))
            .collect(Collectors.toList());
}

Хотя смысл использования Pair все еще неясен в вашем полном подходе, и вы могли бы также избавиться от него.

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