Java 合并包含列表的对象列表

Java 合并包含列表的对象列表,java,java-8,Java,Java 8,我有一个自定义Foo对象列表,每个对象包含两个猫和狗对象列表,如下所示: class Foo { List<Cat> cats; List<Dog> dogs; } class Cat { int id; } class Dog { String name; } class-Foo{ 列出猫; 列出狗的名单; } 班猫{ int-id; } 班犬{ 字符串名; } 我有一个方法,在这里我传递一个列表请求,我想把它展平到一个包含每个请求的Fo

我有一个自定义Foo对象列表,每个对象包含两个猫和狗对象列表,如下所示:

class Foo {
   List<Cat> cats;
   List<Dog> dogs;
}

class Cat {
   int id;
}

class Dog {
   String name;
}
class-Foo{
列出猫;
列出狗的名单;
}
班猫{
int-id;
}
班犬{
字符串名;
}
我有一个方法,在这里我传递一个列表请求,我想把它展平到一个包含每个请求的Foo对象上,猫和狗一起展平。是否有一种干净紧凑的方法来实现这一点

来源列表:

List<Cat> catsForOne = new ArrayList<>(); // add a bunch of cats
List<Cat> catsForTwo = new ArrayList<>(); // add a bunch of cats
List<Dog> dogsForTwo = new ArrayList<>(); // add a bunch of dogs

List<Foo> requests = new ArrayList<>();
Foo one = Foo.builder().cats(catsForOne).build();
Foo two = Foo.builder().dogs(dogsForTwo).cats(catsForTwo).build();

requests.add(one);
requests.add(two);
List catsForOne=new ArrayList();//加一堆猫
List catsForTwo=new ArrayList();//加一堆猫
List dogsForTwo=new ArrayList();//加一堆狗
列表请求=新建ArrayList();
Foo one=Foo.builder().cats(catsForOne.build();
Foo two=Foo.builder().dogs(dogsForTwo).cats(catsForTwo.build();
增加(一项);
增加(两项);
结果应该是:

Foo,列表=catsForOne+catsForTwo,列表=dogsForTwo

这是一个玩具示例,但您可以想象foo大约有5-6个集合(即猫、狗、猪、鸭等),我希望有一个使用Java8的紧凑解决方案。我能做的最简单的一件事就是循环请求,并将所有集合一个接一个地添加到最终结果Foo中


假设Foo、Cat、Dog等来自外部库,因此它们的源代码无法更改。

在Foo中添加一个函数,允许您将列表添加到一起,然后在Foo中循环,将它们添加到一个真正的“扁平”Foo中


您可以单独收集它们,然后创建一个新的
Foo
对象,并将您的
列表分配给它

 List<Dog> collectDogs = foos.stream().flatMap(foo -> foo.getCats().stream())
                       .collect(Collectors.toList());
 List<Cat> collectCats = foos.stream().flatMap(foo -> foo.getDogs().stream())
                      .collect(Collectors.toList());

要使用Java 8流合并多个
Foo
对象,请实现合并方法:

class Foo {
    List<Cat> cats;
    List<Dog> dogs;

    Foo merge(Foo other) {
        this.cats.addAll(other.cats);
        this.dogs.addAll(other.dogs);
        return this;
    }
}

更新

由于
merge()
方法更新当前对象,因此上述代码对于并行使用是不安全的。对于并行使用,
Foo
对象应被视为不可变的

此外,问题还得到了增强,可以说类
Foo
来自外部库,并且不能更改,所以
merge()
方法需要分开

那么,这样做:

class Test {
    public static void test() {
        List<Foo> requests = ...;
        Foo merged = requests.stream().reduce(new Foo(), Test::mergeFoos);
    }

    public static Foo mergeFoos(Foo a, Foo b) {
        Foo merged = new Foo();
        merged.cats = mergeLists(a.cats, b.cats);
        merged.dogs = mergeLists(a.dogs, b.dogs);
        merged.pigs = mergeLists(a.pigs, b.pigs);
        merged.ducks = mergeLists(a.ducks, b.ducks);
        return merged;
    }
    private static <E> List<E> mergeLists(List<E> a, List<E> b) {
        List<E> merged = new ArrayList<>(a.size() + b.size());
        merged.addAll(a);
        merged.addAll(b);
        return merged;
    }
}
Optional<Foo> merged = requests.stream().reduce(Test::merge);
这样就可以了

Foo foo = requests.stream().reduce(new Foo(), (f1, f2) -> {
            f1.cats.addAll(f2.cats);
            f1.dogs.addAll(f2.dogs);
            return f1;
        });

与lambda一样,很容易引入bug。保持简单并多写几行。

您能在请求中提供源列表的定义吗?
list list list=new ArrayList();for(Foo-Foo:傻瓜){list.addAll(Foo.cats);list.addAll(Foo.dogs);}
列表变平。如果这不是你的意思,那么澄清问题。编辑问题,希望它更清楚!所以你想合并多个
Foo
对象吗?@Andreas yes抱歉,这与我目前使用的类似,但我想知道是否有更简洁的方式使用流API或其他Java8功能来表达它。@JohnBaum yes,使用
reduce()
,如中所示。方法名称不重要。它可以被命名为
flatte
,就像这个答案一样。
class Test {
    public static void test() {
        List<Foo> requests = ...;
        Foo merged = requests.stream().reduce(new Foo(), Test::mergeFoos);
    }

    public static Foo mergeFoos(Foo a, Foo b) {
        Foo merged = new Foo();
        merged.cats = mergeLists(a.cats, b.cats);
        merged.dogs = mergeLists(a.dogs, b.dogs);
        merged.pigs = mergeLists(a.pigs, b.pigs);
        merged.ducks = mergeLists(a.ducks, b.ducks);
        return merged;
    }
    private static <E> List<E> mergeLists(List<E> a, List<E> b) {
        List<E> merged = new ArrayList<>(a.size() + b.size());
        merged.addAll(a);
        merged.addAll(b);
        return merged;
    }
}
Optional<Foo> merged = requests.stream().reduce(Test::merge);
Foo foo = requests.stream().reduce(new Foo(), (f1, f2) -> {
            f1.cats.addAll(f2.cats);
            f1.dogs.addAll(f2.dogs);
            return f1;
        });