Как получить список элементов из подмножества списка на основе элементов в другом списке в Java? - PullRequest
0 голосов
/ 20 января 2020

У меня есть List<String>, который представляет идентификаторы (могут быть повторены), элементов из другого списка, который является List<Cheat>, где у каждого Чита есть String ID и List<Integer> RNG. Оба имеют методы доступа в Cheat.

Мне нужно преобразовать этот список ID в список RNG для каждого Cheat, для которого мне был предоставлен ID.

Например, я может иметь 3 чита:

1:{ID:1, RNG:{1,2,3}}
2:{ID:2, RNG{1,2}}
3:{ID:3, RNG:{1}}

и список идентификаторов:

{3,1,1,2}.

Мне нужно будет получить окончательный список {1,1,2,3, 1,2,3,1,2}, то есть ГСЧ Чит 3, затем ГСЧ чит 1, затем ГСЧ чит 1 снова, и, наконец, ГСЧ чит 2.

Если кто-нибудь может помочь мне, это будет оценено. Спасибо.

Я пробовал и не смог:

ImmutableList<Integer> sequenceRngs = cheatIds.stream()
                                              .map(s -> cheats.stream()
                                                                .filter(cheat -> cheat.getId().equals(s))
                                                                .findFirst()
                                                                .map(cheat -> cheat.getRng()))
                                              .flatMap(cheat -> cheat.getRng())
                                              .collect(ListUtils.toImmutableList());

Ответы [ 3 ]

2 голосов
/ 20 января 2020

Одно из возможных решений:

import java.util.List;
import java.util.stream.Collectors;

class Scratch {

    static class Cheat {
        int id;
        List<Integer> rng;

        public Cheat(int id, List<Integer> rng) {
            this.id = id;
            this.rng = rng;
        }
    }

    public static void main(String[] args) {

        List<Cheat> allCheats = List.of(
                new Cheat(1, List.of(1,2,3)),
                new Cheat(2, List.of(1,2)),
                new Cheat(3, List.of(1))
        );

        List<Integer> result = List.of(3, 1, 1, 2).stream()
                .flatMap(id -> allCheats.stream()
                        .filter(cheat -> cheat.id == id)
                        .findFirst().orElseThrow().rng.stream())
                .collect(Collectors.toList());

        System.out.println(result);

    }
}

Ключ заключается в том, чтобы использовать flatMap для получения результата в одной - не вложенной - коллекции в конце.

1 голос
/ 20 января 2020

Лямбда, которую вы передаете flatMap, должна возвращать Stream, а не List. И вам следует разобраться со случаем, когда в потоке нет такого элемента - даже если вы уверены, что он есть. Что-то вроде этого должно сделать:

final ImmutableList<String> sequenceRngs = cheatIds.stream().flatMap(id ->
    cheats.stream().filter(cheat -> id.equals(cheat.getId()))
        .findAny().orElseThrow(IllegalStateException::new)
        .getRng().stream())
    .collect(ListUtils.toImmutableList());

Также я бы предложил преобразовать список читов в карту - это упростило бы код и уменьшило бы сложность поиска с O (n) до O (1). ).

0 голосов
/ 20 января 2020

Это можно сделать, выполнив следующие шаги:

  1. Создать карту из cheatId в RNG id s:

    Map<Integer, List<Integer>> map = cheats.stream()
            .collect(Collectors.toMap(Cheat::getId,
                    cheat -> cheat.getRng().stream().map(RNG::getId).collect(Collectors.toList())));
    
  2. Выполните итерацию по cheatIds, предоставленному в качестве входных данных, и получите соответствующие идентификаторы RNG с карты для сбора в качестве выходных данных:

    List<Integer> output = cheatIds.stream()
            .flatMap(ch -> map.get(ch).stream())
            .collect(Collectors.toList());
    
...