От:
AJ
Дата: 26.04.19 12:06
Оценка:
Коллеги, есть ли какой-то способ упростить следующий код?
import java.util.Arrays;
import java.util.function .Predicate;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
Stream<Object> input = Arrays.stream(new Object[] {
"ABC" , 1, Pair.of(3, 4), Pair.of(1, "2" ), Pair.of(2, 3), "TEST"
});
System.out.println(process(input));
}
public static int process(Stream<Object> input) {
Predicate<Object> isPair = Pair.class ::isInstance;
Predicate<Pair> isLeftInteger = pair -> pair.left instanceof Integer;
Predicate<Pair> isRightInteger = pair -> pair.right instanceof Integer;
// Хотелось бы что-то такое как
// Predicate<Object> isLeftInteger = (Pair) object -> pair.left instanceof Integer;
// Predicate<Object> isRightInteger = (Pair) object -> pair.right instanceof Integer;
// чтобы можно было объединить предикаты как
// input.filter(isPair.and(isLeftInteger).and(isRightInteger))
return input
.filter(e -> isPair.test(e) && isLeftInteger.test(((Pair) e)) && isRightInteger.test((Pair) e))
// и вот здесь есть какой-нибудь избежать всей этой цепочки кастов по второму разу?
.map(e -> ((Integer) ((Pair) e).left + ((Integer) ((Pair) e).right)))
.mapToInt(Integer::intValue)
.sum();
}
static class Pair<L, R> {
static <L, R> Pair<L, R> of(L left, R right) {
Pair<L, R> pair = new Pair<>();
pair.left = left;
pair.right = right;
return pair;
}
L left;
R right;
}
}
Re: Pattern-matching in Java
От:
C0s
Дата: 26.04.19 12:43
Оценка:
Здравствуйте, AJ, Вы писали:
AJ>Коллеги, есть ли какой-то способ упростить следующий код?
пример учебный? (это я к тому, чтобы не писать дурацких вопросов "зачем и кто это сделал
так ?")
AJ> public static int process(Stream<Object> input) {
AJ> Predicate<Object> isPair = Pair.class ::isInstance;
AJ> Predicate<Pair> isLeftInteger = pair -> pair.left instanceof Integer;
AJ> Predicate<Pair> isRightInteger = pair -> pair.right instanceof Integer;
AJ> return input
AJ> .filter(e -> isPair.test(e) && isLeftInteger.test(((Pair) e)) && isRightInteger.test((Pair) e))
AJ> // и вот здесь есть какой-нибудь избежать всей этой цепочки кастов по второму разу?
AJ> .map(e -> ((Integer) ((Pair) e).left + ((Integer) ((Pair) e).right)))
AJ> .mapToInt(Integer::intValue)
AJ> .sum();
// как-то так, наверное
return input.filter(Pair.class ::isInstance).map(Pair.class ::cast).filter(isLeftInteger).filter(isRightInteger)
.mapToInt(p -> ((Integer) p.left) + ((Integer) p.right)).sum();
AJ> }
потенциально, если облегчить условие суммирования до "всех найденных Integer'ов даже в несимметричных по типу парах", то можно было бы сразу после map(cast) сделать разворот в
flatMap(p -> Stream.concat(p.left, p.right)).filter(Integer.class ::isInstance).map(Integer.class ::cast).mapToInt(Integer::intValue)
Re[2]: Pattern-matching in Java
От:
AJ
Дата: 26.04.19 15:07
Оценка:
9 (1)
Здравствуйте, C0s, Вы писали:
C0s>пример учебный? (это я к тому, чтобы не писать дурацких вопросов "зачем и кто это сделал так ?")
Учебный, ага. В реальности я пытаюсь написать плагин к IntelliJ который разбирает дерево из PsiElement'ов и обрабатывает определённые куски кода.
C0s>
C0s>// как-то так, наверное
C0s>return input.filter(Pair.class ::isInstance).map(Pair.class ::cast).filter(isLeftInteger).filter(isRightInteger)
C0s> .mapToInt(p -> ((Integer) p.left) + ((Integer) p.right)).sum();
AJ>> }
C0s>
C0s>потенциально, если облегчить условие суммирования до "всех найденных Integer'ов даже в несимметричных по типу парах", то можно было бы сразу после map(cast) сделать разворот в
C0s>C0s>flatMap(p -> Stream.concat(p.left, p.right)).filter(Integer.class ::isInstance).map(Integer.class ::cast).mapToInt(Integer::intValue)
C0s>
Спасибо, буду знать про cast. Облегчить условие в реальном случае не выйдет.
Накопал тут либу
https://www.vavr.io/ с которой решение выглядит следующим образом
import java.util.Arrays;
import java.util.stream.Stream;
import static io.vavr.API.*;
import static io.vavr.Predicates.*;
public class Main {
public static void main(String[] args) {
Stream<Object> input = Arrays.stream(new Object[] {
"ABC" , 1, Pair.of(3, 4), Pair.of(1, "2" ), Pair.of(2, 3), "TEST"
});
System.out.println(process(input));
}
public static int process(Stream<Object> input) {
return input.map(Main::sumIfPairOfInts).mapToInt(Integer::valueOf).sum();
}
public static Integer sumIfPairOfInts(Object object) {
return Match(object).of(
Case(MyPatterns.$Pair($(instanceOf(Integer.class )), $(instanceOf(Integer.class ))), (left, right) -> left + right),
Case($(), () -> 0));
}
}
Класс ниже процессится их кодо-генератором через Maven
import io.vavr.Tuple;
import io.vavr.Tuple2;
import io.vavr.match.annotation.Patterns;
import io.vavr.match.annotation.Unapply;
@Patterns
class My {
@Unapply
static <L, R> Tuple2<L, R> Pair(Pair<L, R> pair) {
return Tuple.of(pair.left, pair.right);
}
}
На выходе получается вот такая штуковина
// @formatter:off
// CHECKSTYLE:OFF
import io.vavr.API.Match.Pattern;
import io.vavr.API.Match.Pattern2;
// GENERATED BY VAVR <<>> derived from My
@SuppressWarnings("deprecation" )
public final class MyPatterns {
private MyPatterns() {
}
public static <L, R, _1 extends L, _2 extends R> Pattern2<Pair<L, R>, _1, _2> $Pair(Pattern<_1, ?> p1, Pattern<_2, ?> p2) {
return Pattern2.of(Pair.class , p1, p2, My::Pair);
}
}
// CHECKSTYLE:ON
// @formatter:on
public class Pair<L, R> {
L left;
R right;
static <L, R> Pair<L, R> of(L left, R right) {
Pair<L, R> pair = new Pair<>();
pair.left = left;
pair.right = right;
return pair;
}
}
Re: Pattern-matching in Java
От:
bzig
Дата: 27.04.19 23:05
Оценка:
Можно так
public static <T, L, R> Function<T, Pair<L,R>> toPair(Class<L> leftCls, Class<R> rightCls) {
return object -> object instanceof Pair
&& ((Pair)object).left != null
&& ((Pair)object).right!= null
&& leftCls.isAssignableFrom(((Pair)object).left.class)
&& rightCls.isAssignableFrom(((Pair)object).right.class)
? (Pair<L,R>)object
: null
}
input
.map(toPair(Integer.class, Integer.class))
.filter(Objects::notNull)
...
Можно вместо null возвращать Stream<Pair<L,R>> (ну и сигнатуру метода поменять), тогда вызов будет
input
.flatMap(toPair(Integer.class, Integer.class))
...
Re: Pattern-matching in Java
От:
vsb
Дата: 28.04.19 08:16
Оценка:
+1
Сразу напрашивается сделать после фильтра по типу map который просто прокастует в нужный тип. Тогда всё, что ниже, будет иметь дело с конкретным типом и кастовать не нужно. Если хочется вынести проверку типа и каст в одну операцию, можно использовать flatMap.
Re: Pattern-matching in Java
От:
Буравчик
Дата: 28.04.19 08:59
Оценка:
Здравствуйте, AJ, Вы писали:
AJ>Коллеги, есть ли какой-то способ упростить следующий код?
Так?
public static int process(Stream<Object> input) {
...
return input
.filter(isPair)
.map(Pair.class ::cast)
.filter(e -> isLeftInteger.test(e) && isRightInteger.test(e))
.map(e -> (Pair<Integer,Integer>) e)
.map(e -> e.left + e.right)
.mapToInt(Integer::intValue)
.sum();
Best regards, Буравчик
Re: Pattern-matching in Java
От:
·
Дата: 03.05.19 10:57
Оценка:
Здравствуйте, AJ, Вы писали:
AJ>Коллеги, есть ли какой-то способ упростить следующий код?
В лоб решение как-то так:
int process(final Stream<Object> input) {
return input
.filter(Pair.class ::isInstance)
.map(Pair.class ::cast)
.filter(pair -> pair.getLeft() instanceof Integer)
.filter(pair -> pair.getRight() instanceof Integer)
.map(pair -> ((Pair<Integer,Integer>) pair))
.mapToInt(pair -> pair.getLeft() + pair.getRight())
.sum();
}
Магию с парой можно вынести в утилитный метод
static <L, R> Function<Object, Stream<Pair<L, R>>> pairOf(Class<L> l, Class<R> r) {
return o -> {
if (!(o instanceof Pair))
return Stream.empty();
final Pair p = (Pair) o;
if ( !l.isInstance(p.getLeft()))
return Stream.empty();
if ( !r.isInstance(p.getRight()))
return Stream.empty();
return Stream.of(p);
};
}
Тогда можно писать как-то так:
int process(final Stream<Object> input) {
return input
.flatMap(pairOf(Integer.class , Integer.class ))
.mapToInt(pair -> pair.getLeft() + pair.getRight())
.sum();
}
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Пока на собственное сообщение не было ответов, его можно удалить.
Удалить