Как собирать и объединять различные объекты в Java Stream в правильном порядке? - PullRequest
0 голосов
/ 30 июня 2018

У меня есть два объекта:

String y = "Y"
String r = "R"

как собрать и объединить эти значения с Java Stream для получения этой строки: "YYRYYRYYRYY"?

Поток может быть бесконечным, но должен начинаться с YY и заканчиваться YY, но каждое третье значение должно быть R

Ответы [ 3 ]

0 голосов
/ 30 июня 2018

Если вы хотите использовать поток, вы должны сделать что-то вроде этого:

final long iterateLimit = 20;
final String sequence = "YYR";
final String suffix = "YY";
final String yyrString = Stream.generate(() -> sequence)
                               .limit(iterateLimit)
                               .collect(Collectors.joining())
                               .concat(suffix);

Я предлагаю сгенерировать последовательность из " ГГ " и добавить суффикс" ГГ " после создания строки.

0 голосов
/ 01 июля 2018

В вашем требовании есть противоречие: «Поток может быть бесконечным, но должен… заканчиваться YY».

Из того, что я вижу, вам нужен просто повторяющийся поток Y, Y, R, который может быть построен как

String y = "Y";
String r = "R";
String[] toRepeat = { y, y, r };
Stream.generate(() -> toRepeat).flatMap(Arrays::stream)

чтобы вы могли напечатать эту бесконечную последовательность:

Stream.generate(() -> toRepeat).flatMap(Arrays::stream)
      .forEach(System.out::println);

Чтобы превратить его в конечную последовательность, оканчивающуюся на «уу», используйте предел, который на единицу меньше числа, делимого на три, например, пять, восемь, одиннадцать, 332 и т. д.

Затем вы можете собрать / объединить поток в String:

String[] toRepeat = { y, y, r };
String seq = Stream.generate(() -> toRepeat).flatMap(Arrays::stream)
      .limit(11)
      .collect(Collectors.joining());
System.out.println(seq);

Вместо .collect(Collectors.joining()) вы также можете использовать .reduce("", String::concat), но первый обычно более эффективен.

Другой подход заключается в переборе всех последовательностей, удовлетворяющих вашему требованию:

Stream.iterate(y+y, s -> s+r+y+y)
    .forEach(System.out::println);

Это можно использовать для поиска n-й действительной последовательности:

Stream.iterate(y+y, s -> s+r+y+y)
    .skip(10)
    .findFirst()
    .ifPresent(System.out::println);
0 голосов
/ 30 июня 2018

Конечная последовательность

Предположим, вы хотите создать конечную последовательность символов, содержащую Y или R, случайным образом , просто создайте некоторый метод next() и вызывайте его повторно:

public final class SequenceGenerator {
    private final String[] elements;
    private final Random rnd;

    public SequenceGenerator(Collection<String> elements) {
        this.elements = elements.toArray(new String[elements.size()]);
        rnd = new Random();
    }

    public String next() {
        return elements[rnd.nextInt(elements.length)];
    }

    public String generate(int amountOfElements) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < amountOfElements; i++) {
            sb.append(next());
        }
        return sb.toString();
    }
}

Класс берет набор возможных элементов для рисования, а его методы next выбирают один случайным образом. Метод generate вызывает его несколько раз и добавляет нарисованные элементы.

Простое использование:

SequenceGenerator gen = new SequenceGenerator(List.of("Y", "R"));
System.out.println(gen.generate(11));

Может печатать что-то вроде:

YYRYYRYYRYY

Бесконечный поток

Вы также можете использовать API Stream здесь для создания бесконечного потока:

SequenceGenerator gen = new SequenceGenerator(List.of("Y", "R"));
Stream<String> sequence = Stream.generate(gen::next);

Редактировать: YY и R

Как вы сказали, вы хотите, чтобы поток начинался и заканчивался YY, а также имел R в каждой третьей позиции, нам нужно немного изменить next(). Прежде всего мы добавляем поле int amount для отслеживания звонков. Затем next() изменяется для учета YY в начале и R. Точно так же generate должен быть изменен, чтобы учесть YY в конце. Вариант Stream может остаться неизменным, поскольку он использует измененный next() и не должен учитывать YY в конце, поскольку он бесконечен.

public final class SequenceGenerator {
    // ...
    private int amount;

    public SequenceGenerator(Collection<String> elements) {
        // ...
        amount = 0;
    }

    public String next() {
        // Start must be 'YY'
        if (amount == 0 || amount == 1) {
            amount++;
            return "Y";
        }

        // Every third must be 'R'
        if (amount % 3 == 0) {
            amount++;
            return "R";
        }

        // Pick a random element
        amount++;
        return elements[rnd.nextInt(elements.length)];
    }

    public String generate(int amountOfElements) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < amountOfElements - 2; i++) {
            sb.append(next());
        }

        // End must be 'YY'
        sb.append("YY");

        return sb.toString();
    }
}

На самом деле есть еще одно требование, которое мы должны учитывать. Объединение YY в конце должно быть действительным в отношении правила, которое заставляет R в каждой третьей позиции. Таким образом, для generate значение amountOfElements должно быть на два больше значения, которое делится на 3, иначе полученное значение будет недействительным.

И мы должны учитывать крайние случаи, amountOfElements должно быть не менее 5, каждая меньшая последовательность недопустима. YYRYY является первой действительной последовательностью. Модифицированный метод:

public String generate(int amountOfElements) {
    if (amountOfElements < 5 || (amountOfElements - 2) % 3 != 0) {
        throw new IllegalArgumentException("Invalid sequence length");
    }
    // ...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...