2016-12-25 2 views
12

У меня есть поток BiFunctions, который я хочу свести к одному BiFunction.Состав BiFunctions

Чтобы быть более конкретным у меня есть поток BiFunctions

BiFunction<x,y,y> 

где х и у обозначают типы аргументов.

Предполагая, что у меня есть две функции

f (x, y) -> y 
g (x, y) -> y 

Я хочу, чтобы составить их функции

h(x, y) -> f(x, g(x, y)) 

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

+1

Вы ищете Stream.reduce, которому необходимо дать лямбду, которая принимает f и g и возвращает h. –

ответ

12

Использование x=Integer и y=String, можно определить f и g как:

BiFunction<Integer, String, String> f = (i, s) -> i + "-f-" + s; 
BiFunction<Integer, String, String> g = (i, s) -> i + "-g-" + s; 

И функция h может быть построен с использованием сокращения:

BiFunction<Integer, String, String> h = Stream.of(f, g) 
     .reduce((f_, g_) -> (i, s) -> f_.apply(i, g_.apply(i, s))) 
     .get(); //we know the stream is not empty so we can call get directly 

Если применить h к 1 и "s" , он вернет 1-f-1-g-s.

+2

Обратите внимание, что 'Stream.of (f, g) .reduce ((f_, g_) -> ...' является избыточным, но в этом случае он позволяет обобщать на более чем две функции ввода. – immibis

+3

Да, это идея - только с двумя функциями нет необходимости в потоке. – assylias

8

В качестве небольшого изменения в answer by assylias: В зависимости от характера приложения, вы можете также использовать Stream#reduce метод, который принимает идентичности в качестве первого аргумента, который в данном случае является «идентичностью BiFunction» (фактически, проекция на второй аргумент).

import java.util.function.BiFunction; 
import java.util.stream.Stream; 

public class BiFunctionsComposition 
{ 
    public static void main(String[] args) 
    { 
     BiFunction<String, String, String> f = (x,y) -> "f("+x+","+y+")"; 
     BiFunction<String, String, String> g = (x,y) -> "g("+x+","+y+")"; 

     BiFunction<String, String, String> h = Stream.of(f, g) 
      .reduce((x,y) -> y, (ff,gg) -> (x,y) -> ff.apply(x, gg.apply(x, y))); 

     String result = h.apply("A", "B"); 
     System.out.println(result); // Prints f(A,g(A,B)) 
    } 
} 
+0

Есть ли какие-либо преимущества перед принятым ответом, кроме того, что мы можем отказаться от вызова get()? – lup3x

+3

Это зависит: если вы хотите предложить функцию типа BiFunction compose (Stream > stream) ', то вы * можете * не знать, пуст ли пуст или нет. Поэтому вам нужно сначала проверить« Необязательный », чтобы увидеть, пуст ли он. Я думаю, используя функцию« identity » для этого случая разумно и удобно. – Marco13