Как реализовать следующий алгоритм сортировки Bubble в функциональном (Java 8) способом?
public static final <T extends Comparable<T>> List<T> imperativeBubbleSort(List<T> list) {
int len = list == null? 0: list.size();
for(int j = len-1; j > 0; j--) {
for(int k = 0; k < j; k++) {
if(list.get(k+1).compareTo(list.get(k)) < 0) {
list.add(k, list.remove(k+1));
}
}
}
return list;
}
Это будет зависеть от того, что вы подразумеваете под функциональностью. Если вы имеете в виду просто передавать функции в качестве объектов первого класса, то вы должны изменить свою подпись метода:
public static final <T> List<T> imperativeBubbleSort(List<T> list, Comparator<T> comparisonFunction)
Таким образом, логика сравнения может быть предоставлена в качестве аргумента.
Если вы имеете в виду, что вы будете полностью функционировать, а вовсе не процедурные, я бы назвал это анти-шаблоном. Несмотря на то, что вы можете услышать, Java 8 не полностью поддерживает функциональное программирование. Ключевой особенностью, которой он отсутствует, является оптимизация хвостового вызова. Без него вид программирования без циклы, который определяет функциональное программирование, скорее всего, приведет к сбою вашего JVM для относительно небольших значений.
Более подробную информацию об оптимизации хвостовых вызовов и JVM можно найти здесь: http://www.drdobbs.com/jvm/tail-call-optimization-and-java/240167044
Самый короткий путь, о котором я мог думать, - это следовать. Там, где вводится listForBubbleSort, и вызывается bubbleSorted.
List<Integer> listForBubbleSort = Arrays.asList(5, 4, 3, 7, 6, 9, 11, 10, 21);
final List<Integer> copiedList = new ArrayList<>(listForBubbleSort);
copiedList.add(Integer.MAX_VALUE);
final List<Integer> bubbleSorted = new ArrayList<>();
copiedList.stream()
.reduce((c, e) ->
{
if ( c < e ){
bubbleSorted.add(c);
return e;
}
else
{
bubbleSorted.add(e);
return c;
}
}
);
System.out.println(bubbleSorted);
Я все еще чувствую, что если бы мы могли создать пользовательский коллекционер и просто передать коллекционеру коллекцию потока, это было бы здорово. Подобно тому, как мы передаем поток (toList()) в поток. Но все же, изучая Java 8, нужно больше времени для создания того же. Если кто-то уже создал пользовательский коллекционер, поделитесь им.
Я не думаю, что Java 8 предоставит большую помощь в этом случае, чтобы написать сортировку пузырьков в функциональном стиле.
Например, эта реализация реализации Bubble sort в Haskell может быть смоделирована на Java следующим образом. Он более функциональный, поскольку он использует рекурсию вместо итерации, но все же Java 8 не имеет таких функций, как сопоставление образцов, конкатенация списков и т.д., Чтобы выразить алгоритмы в более функциональном стиле.
public static final <T extends Comparable<T>> List<T> functionalBubbleSort(List<T> list) {
for (int i = 0; i < list.size(); i++) {
list = onePassSort(list);
}
return list;
}
public static final <T extends Comparable<T>> List<T> onePassSort(List<T> list) {
if (list.size() == 0 || list.size() == 1) {
return list;
} else {
T first = list.get(0);
T second = list.get(1);
if (first.compareTo(second) < 0) {
return merge(first, onePassSort(list.subList(1, list.size())));
} else {
return merge(second, onePassSort(merge(first, list.subList(2, list.size()))));
}
}
}
public static <T> List<T> merge(T head, List<T> tail) {
List<T> result = new ArrayList<>();
result.add(head);
result.addAll(tail);
return result;
}
Упрощенная версия с использованием Java 8 API
public static int[] bubbleSort(int[] array) {
BiConsumer<int[],Integer> swapValueIf = (a,j) -> {
if(a[j] > a[j+1]) {
int temp = a[j];
array[j] = a[j+1];
array[j+1] = temp;
}
};
IntStream.range(0, array.length - 1).forEach( i -> IntStream.range(0, array.length - 1).forEach(j -> swapValueIf.accept(array, j)));
return array;
}
Я получил правдоподобный подход:
@SuppressWarnings("unchecked") public static final <T extends Comparable<T>> List<T> declarativeBubbleSort(final List<T> list) {
List<T> result = new ArrayList<>(list);
int len = result.size();
Function<Function<Object, Object>, IntConsumer> consumer =
recur ->
length ->
IntStream.range(0, length)
.filter(i -> IntStream.range(0, len - i - 1)
.filter(j -> result.get(j+1).compareTo(result.get(j)) < 0)
.mapToObj(j-> {
T swap = result.remove(j+1);
result.add(j, swap);
return swap;
}).count() > 0)
.max().ifPresent(IntConsumer.class.cast(recur.apply(Function.class.cast(recur))));
consumer.apply(Function.class.cast(consumer)).accept(len);
return result;
}
Я знаю, что я все еще немного поважен, но для такого рода мне трудно сделать это полностью декларативным на Java и не наказывать за производительность.
Если вы хотите быть параллельным, тогда:
@SuppressWarnings("unchecked") public static final <T extends Comparable<T>> List<T> declarativeParallelBubbleSort(final List<T> list) {
List<T> result = new ArrayList<>(list);
int len = result.size();
Function<Function<Object, Object>, IntConsumer> consumer =
recur ->
length ->
IntStream.range(0, length)
.filter(i -> IntStream.range(0, len - i - 1)
.filter(j -> result.get(j+1).compareTo(result.get(j)) < 0)
.parallel()
.mapToObj(j-> {
synchronized(result) {
T swap = result.remove(j+1);
result.add(j, swap);
return swap;
}
}).count() > 0)
.max().ifPresent(IntConsumer.class.cast(recur.apply(Function.class.cast(recur))));
consumer.apply(Function.class.cast(consumer)).accept(len);
return result;
}