2016-08-29 2 views
0

Есть ли лучший функциональный тип интерфейса для хранения этого выражения лямбда? И есть ли чистый способ заменить петли потоками? Ищете способ сделать это с более выразительным кодом.Как вы производите произвольное выражение лямбда в Java 8?

Проблема заключается в анализе 2D-сетки (сетки) и сохранении результатов в простом классе значений (результаты). Нужно идти вверх, вниз, влево и прямо вдоль сетки, начиная с заданной точки (строка, col). Каждый из четырех циклов, которые нужно пройти, содержит точный код, явное нарушение DRY.

Мое решение состоит в том, чтобы написать четыре петли и вызвать метод в каждом. Это метод throwaway, поэтому я использовал лямбду Java 8 с доступом к сеткам результатов &, потому что они в лексической области.

Predicate<int[]> countAndBreak = (int[] coord) -> { 
    int r = coord[0]; 
    int c = coord[1]; 
    if (grid[r][c] == Grid.YUMMYCANDY) 
     results.count++; 
    if (grid[r][c] == Grid.WALL) 
     return true; 
    else 
     return false; 
}; 

for (int r = row; r < grid.length; r++) { 
    if (countAndBreak.test(new int[] { r, col })) 
     break; 
} 
for (int r = row; r >= 0; r--) { 
    if (countAndBreak.test(new int[] { r, col })) 
     break; 
} 
for (int c = col; c < grid[0].length; c++) { 
    if (countAndBreak.test(new int[] { row, c })) 
     break; 
} 
for (int c = col; c >= 0; c--) { 
    if (countAndBreak.test(new int[] { row, c })) 
     break; 
} 
+1

Не уверен в этом решении, но я знаю, что такая логика станет намного проще с «takeWhile» Java 9. – Zircon

+4

Поскольку это то, что принимает один параметр и возвращает 'boolean',' Predicate' является подходящим функциональным интерфейсом для использования. Вы можете написать 'if (grid [r] [c] == Grid.WALL) return true; else return false; 'просто как' return grid [r] [c] == Grid.WALL; ' – Jesper

+0

Отличная уловка по булевому, @Jesper. Обратите внимание, что единственная причина, по которой этот предикат принимает один параметр, заключается в том, что я перепутал два параметра в один, используя массив, временный кортеж для Java. – MikeJfromVA

ответ

3

Ну, если вы не создали свой собственный функциональный интерфейс, вы не получите более подходящий тип соответствия. Но большим препятствием в этом контексте является использование int[], а не целевого типа. Пребывание с этими типами, то лучшее, что вы можете получить, как

Predicate<int[]> atWall = coord -> grid[coord[0]][coord[1]] == Grid.WALL; 
Predicate<int[]> isCandy = coord -> grid[coord[0]][coord[1]] == Grid.YUMMYCANDY; 
int[] curr={ row, col}; 
results.count += countUntil(curr, p -> new int[]{ p[0]+1, p[1] }, atWall, isCandy); 
results.count += countUntil(curr, p -> new int[]{ p[0]-1, p[1] }, atWall, isCandy); 
results.count += countUntil(curr, p -> new int[]{ p[0], p[1]+1 }, atWall, isCandy); 
results.count += countUntil(curr, p -> new int[]{ p[0], p[1]-1 }, atWall, isCandy); 

… 

static <T> int countUntil(
    T start, UnaryOperator<T> iterate, Predicate<T> until, Predicate<T> countable) { 

    int[] holder={ 0 }; 
    Stream.iterate(start, iterate).anyMatch(element -> { 
     if(until.test(element)) return true; 
     if(countable.test(element)) holder[0]++; 
     return false; 
    }); 
    return holder[0]; 
} 

абстрагирования наиболее несовершенные части, то есть, когда вы решите заменить int[] выделенным координат типа, вы не должны изменить метод countUntil. С другой стороны, метод countUntil скрывает неприятное использование изменяемого состояния, которое может быть заменено чистым раствором при переходе на Java 9, без необходимости изменения вызывающего:

static <T> int countUntil(
    T start, UnaryOperator<T> iterate, Predicate<T> until, Predicate<T> countable) { 

    return (int)Stream.iterate(start, until.negate(), iterate).filter(countable).count(); 
} 

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

Смежные вопросы