Есть ли способ вызвать findMatch рекурсивно? - PullRequest
2 голосов
/ 19 апреля 2020

В этом вопросе мне необходимо написать метод findMatch, который принимает «поток» (IFL предназначен для имитации c потока) и находит первый элемент потока, который передает предикат. Моя попытка заключается в следующем:

import java.util.function.Predicate;
import java.util.Optional;
import java.util.ArrayList;
import java.util.List;

class IFL<T> {
    Supplier<T> head;
    Supplier<IFL<T>> tail;

    IFL(Supplier<T> head, Supplier<IFL<T>> tail) {
        this.head = head;
        this.tail = tail;
    }

    static <T> IFL<T> of(List<? extends T> list) {
        return new IFL<T>(
            () -> list.get(0),
            () -> IFL.of(list.subList(1, list.size()))) {
        };
    }       

    Optional<T> findMatch(Predicate<? super T> predicate) {
        if (predicate.test(head.get())) {
            return Optional.of(this.head.get());
        } else {
            if (this.tail.get().findMatch(predicate).isPresent()) {
                return this.tail.get().findMatch(predicate);
            }
            return Optional.empty();
        }
    }
}

Проблема, с которой я сталкиваюсь, заключается в том, что блок else в моем методе findMatch, похоже, выполняет только оператор return вместо рекурсивного вызова самого себя, как я полагаю, что это должно , Есть ли в любом случае, чтобы убедиться, что он делает?

Обновление: я получил код для работы для второй строки ввода. Однако выполнение третьей строки ввода приводит к IndexOutOfBoundsException в jshell.

Ввод выглядит следующим образом

    IFL<String> list = IFL.of(Arrays.asList("three", "little", "pigs"))
    list.findMatch(str -> str.length() == 6)
    list.findMatch(str -> str.length() < 4)

Ответы [ 3 ]

1 голос
/ 19 апреля 2020

Вы можете сделать это следующим образом:

Проверяя размер списка в конструкторе, а также проверяя недействительность this.head в методе findMatch();

Вам не нужно проверять if (this.tail.get().findMatch(predicate).isPresent()), а затем снова вызвать findMatch метод.

class IFL<T> {
   Supplier<T> head;
   Supplier<IFL<T>> tail;

   IFL(Supplier<T> head, Supplier<IFL<T>> tail) {
     this.head = head;
     this.tail = tail;
   }

   static <T> IFL<T> of(List<? extends T> list) {

     if (list.isEmpty())
         return new IFL<>(null, null);

     return new IFL<T>(
            () -> list.get(0),
            () -> IFL.of(list.subList(1, list.size()))) {
     };
   }

  Optional<T> findMatch(Predicate<? super T> predicate) {
     if (this.head == null)
        return Optional.empty();
     return predicate.test(head.get()) ?
         Optional.of(this.head.get()) :this.tail.get().findMatch(predicate);
  }
}   
0 голосов
/ 19 апреля 2020

Попробуйте с приведенным ниже кодом

import java.util.Arrays;
import java.util.function.Predicate;
import java.util.Optional;
import java.util.List;
import java.util.function.Supplier;

class IFL<T> {
    Supplier<T> head;
    Supplier<IFL<T>> tail;
    List<? extends T> list;

    IFL(Supplier<T> head, Supplier<IFL<T>> tail, List<? extends T> list) {
        this.head = head;
        this.tail = tail;
        this.list = list;
    }

    static <T> IFL<T> of(List<? extends T> list) {
        return new IFL<T>(
                () -> list.get(0),
                () -> IFL.of(list.subList(1, list.size())), list) {
        };
    }

    Optional<T> findMatch(Predicate<? super T> predicate) {
        if (!list.isEmpty() && predicate.test(head.get())) {
            return Optional.of(this.head.get());
        } else {
            if (!list.isEmpty() && this.tail.get().findMatch(predicate).isPresent()) {
                return this.tail.get().findMatch(predicate);
            }
            return Optional.empty();
        }
    }

    public static void main(String...args) {
        IFL<String> list = IFL.of(Arrays.asList("three", "little", "pigs"));
        System.out.println(list.findMatch(str -> str.length() == 6));
        System.out.println(list.findMatch(str -> str.length() < 4));
    }
}

Надеюсь, это поможет !!!

0 голосов
/ 19 апреля 2020

IndexOutOfBoundsException выбрасывается для недопустимого значения индекса конечной точки для метода List#subList (fromIndex < 0 || toIndex > size || fromIndex > toIndex)

в вашем методе IFL#of, вам нужно проверить, имеет ли данный список размер 1. Если это так, установите tail в пустой список.

static <T> IFL<T> of(List<? extends T> list) {
 return new IFL<T>(
     () -> list.get(0),
     () -> IFL.of(list.size == 1 ? new ArrayList<T>() : list.subList(1, list.size()))) {
 };
...