Java - Как получить список элементов лучше при определенных условиях - PullRequest
0 голосов
/ 08 января 2019
Solution{
  String question
  String answer

  public Solution(String question,String answer){
  ...
  }
}

List<Solution> solutions = new ArrayList<>();

Arrays.asList(
    new Solution("Index1","a"),
    new Solution("Index2","b"),
    new Solution("Index3","c"),
    new Solution("Index4","d"),
    new Solution("Index5","ae"),
    new Solution("Index1","afg"),
    new Solution("Index2","adfg"),
    new Solution("Index1","ag"),
    new Solution("Index2","a"),
    new Solution("Index3","a"),
    new Solution("Index4","a"),
    new Solution("Index5","a"),
    new Solution("Index1","arrr"),
    new Solution("Index2","a"),
    new Solution("Index3","a"));

Я всегда хочу получить последние два набора, начиная с Index1, которые

new Solution("Index1","ag"),
new Solution("Index2","a"),
new Solution("Index3","a"),
new Solution("Index4","a"),
new Solution("Index5","a"),
new Solution("Index1","arrr"),
new Solution("Index2","a"),
new Solution("Index3","a"))

но я не уверен, что это лучший способ сделать это. Я могу думать о реверсе списка и затем иметь счетчик на Index1, который начинается с 0 затем выполните цикл while, чтобы добавить его в список, пока счетчик не достигнет 2. Не уверен, возможно ли это с потоками.

Ответы [ 3 ]

0 голосов
/ 08 января 2019

Это решение немного сложнее, потому что критерии фильтрации состоят из нескольких частей, но это можно сделать, посчитав количество раз, когда был замечен индекс вопроса, самое большее, добавив только 2 решения на вопрос, и остановив один раз Index1 был замечен дважды.

Объектом фильтрации для этого критерия будет:

public class SolutionFilter implements Predicate<Solution> {

    private final Map<String, Integer> counter = new HashMap<>();

    @Override
    public boolean test(Solution solution) {

        Integer index1Count = counter.get("Index1");

        if (index1Count != null && index1Count == 2) {
            return false;
        }

        Integer count = counter.get(solution.getQuestion());

        if (count == null) {
            counter.put(solution.getQuestion(), 1);
            return true;
        }
        else if (count == 1) {
            counter.put(solution.getQuestion(), 2);
            return true;
        }
        else {
            return false;
        }
    }
}

Чтобы убедиться, что решения добавляются в обратном порядке, выполняется цикл, начиная с конца и продвигаясь к началу списка solutions. Аналогично, чтобы гарантировать, что список вывода не в обратном порядке, используется Deque, и соответствующие Solution s добавляются к заголовку Deque:

public static void main(final String[] args) {
    List<Solution> solutions = Arrays.asList(
        new Solution("Index1","a"),
        new Solution("Index2","b"),
        new Solution("Index3","c"),
        new Solution("Index4","d"),
        new Solution("Index5","ae"),
        new Solution("Index1","afg"),
        new Solution("Index2","adfg"),
        new Solution("Index1","ag"),
        new Solution("Index2","a"),
        new Solution("Index3","a"),
        new Solution("Index4","a"),
        new Solution("Index5","a"),
        new Solution("Index1","arrr"),
        new Solution("Index2","a"),
        new Solution("Index3","a")
    );

    SolutionFilter filter = new SolutionFilter();
    Deque<Solution> filteredSolutions = new LinkedList<>();

    for (int i = solutions.size() - 1; i > 0; i--) {

        Solution solution = solutions.get(i);

        if (filter.test(solution)) {
            filteredSolutions.addFirst(solution);
        }
    }

    System.out.println(filteredSolutions);
}

Это приводит к следующему выводу:

[{Index1: ag}, {Index2: a}, {Index3: a}, {Index4: a}, {Index5: a}, {Index1: arrr}, {Index2: a}, {Index3: a}]

Это может быть достигнуто с помощью Stream, но это может быть более сложным.

0 голосов
/ 08 января 2019

Я думаю, что самый простой способ - получить позиции, в которых Index1 появляется в списке решений. Они представляют потенциальную стартовую позицию подсписка. Вы можете сделать это, используя IntStream над индексами в списке решений. Затем возьмите точку с начала до конца в качестве начала подсписка, который идет до конца списка.

    List<Integer> starts = IntStream.range(0, solutions.size())
                                    .filter(i -> solutions.get(i).getQuestion().equals("Index1"))
                                    .boxed()
                                    .collect(toList());
    if (starts.size() < 2) {
        // not sure what you want to do in this case
    } else {
        List<Solution> lastTwoSets = solutions.subList(starts.get(starts.size()-2), solutions.size());
        lastTwoSets.forEach(System.out::println);
    }

Мне приходит в голову, что использование int[] вместо List<Integer> делает вещи немного более эффективными, а также более краткими. Техника в остальном практически одинакова.

    int[] starts = IntStream.range(0, solutions.size())
                            .filter(i -> solutions.get(i).question.equals("Index1"))
                            .toArray();
    if (starts.length < 2) {
        // not sure what you want to do in this case
    } else {
        List<Solution> lastTwoSets = solutions.subList(starts[starts.length-2], solutions.size());
        lastTwoSets.forEach(System.out::println);
    }
0 голосов
/ 08 января 2019

С обычным циклом for это немного проще, чем с потоками. Вы можете перебирать список и отслеживать индексы последних двух вхождений Index1. Если вы знаете индекс от второго до последнего, вы можете использовать метод subList, чтобы получить окончательный список.

Чтобы сделать это быстрее, вы можете выполнить итерацию в обратном направлении от конца и найти первые два вхождения. Затем вы можете остановиться, когда вы нажмете Index1 во второй раз.

Этот пример повторяется с самого начала:

int firstIndex = -1;
int secondIndex = -1;

for (int i = 0; i < solutions.size(); i++) {
    if (solutions.get(i).getQuestion().equals("Index1")) {
        firstIndex = secondIndex;
        secondIndex = i;
    }
}

if (firstIndex == -1) {
    // There weren't two occurrences of "Index1", so I return the whole list.
    return solutions;
}

return solutions.subList(firstIndex, solutions.size());

Обратите внимание, что метод subList возвращает представление вашего исходного списка. Это означает, что он не будет перебирать ваш список во второй раз, когда вы его вызываете. Это также означает, что при изменении исходного списка изменения будут отражены в подсписке.

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