Как стать автором
Обновить

Комментарии 12

Последовательность начинается числом, удовлетворяющим предикату fizz

(6, 789, 10)

Тут и 6 и 9 удовлетворяют предикату fizz, при этом 6 не входит, а 9 входит. Почему так?

Последовательность началась и теперь мы проверяем только "закрывающий" предикат.

В качестве альтернативы, вместо чисел можно использовать строки. Пример:

@Test
@DisplayName("Filter out lines between [```java] and [```].")
void extract_all_java_code_snippets_from_markdown_document() {
    var markdown = """
            # Hello, World!
            The following code snippet is written in Java:
            ```java
            System.out.println("Hello, World!");
            ```
            The following code snippet is written in Kotlin:
            ```kotlin
            println("Hello, World!")
            ```
            """;
    
    Predicate<String> fizz = "```java"::equals;
    Predicate<String> buzz = "```"::equals;
    
    // TODO: Define the predicate
    Predicate<String> fizzBuzz = i -> false;

    assertThat(markdown.lines().filter(fizzBuzz))
            .as("Java code snippets")
            .containsExactly("""
                    System.out.println("Hello, World!");
                    """);
}

.containsExactly("""
System.out.println("Hello, World!");""");

В этом кейсе работает такой вариант:

var started = new AtomicBoolean();
Predicate<String> fizzBuzz = i -> {
    if (started.get()) {
        if (buzz.test(i)) {
            started.set(false);
            return false;
        } else {
            return true;
        }
    } else {
        started.set(fizz.test(i));
        return false;
    }
};

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

var fizzBuzz = new IntPredicate {
    boolean state;
  
    @Override 
    public boolean test() {
      ...
    }
};

Для чисел аналогичный подход

Можете предложить своё решение. С интересом посмотрим.

Дело не в решении, а в задаче скорее. Смотрите, вы всю статью показываете как, комбинируя предикаты, добиться результатов из примеров. В последней задаче ожидаешь какого-то аналогичного решения. Т.е. комбинации логических операторов. Начинаешь думать, понимая, что так не получится. Периодически отбрасываешь вариант с состоянием, как нечто чужеродное в данном контексте. А потом выясняешь, что так и надо было. Вот от этого разочарование.

Ну и в остальном, предикаты с состоянием это так себе идея в реальной жизни. Даже без учета того, что кто-то может засунуть их в parallelStream

Если вы про решение последней задачки, то решение довольно простое. Нужно исключить начало интервала и конец, значит остаток от деления на 3 и на 5 должен быть больше 0. Также нужно исключить общие множители, значит остатки от деления не должны быть равны. И нужно исключить наложение отрезков, т.е. когда остаток от деления равен 4 (границы не включаются). Если оформлять решение через демонстрированный в статье метод предикатов, то получаем:

решение
var numbers = IntStream.rangeClosed(1, 30);
IntPredicate startFizz = i -> i % 3 > 0;
IntPredicate startFizzException = i -> i % 5 == 4;
IntPredicate endBuzz = i -> (i % 3) < (i % 5);
assertThat(numbers.filter(startFizz.or(startFizzException).and(endBuzz)))
        .as("Numbers between integers divisible by three and by five")
        .containsExactly(4, 7, 8, 9, 13, 14, 19, 22, 23, 24, 28, 29);

Действительно, состояние можно затащить внутрь и сэкономить на AtomicBoolean.

Последовательность начинается числом, удовлетворяющим предикату fizz, и заканчивается числом, удовлетворяющим предикату buzz.

Последовательность начатая 6-кой во время 9-ки ещё не завершилась - она завершится только на 10-ке и 9-ка окажется внутри последовательности [6, 10].

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации