Java 在对象之间切换关联方向

Java 在对象之间切换关联方向,java,java-8,java-stream,Java,Java 8,Java Stream,假设我有一门课foo: class foo { String someString; List<String> someList; } 将成为 arr2: [ foo { someString: 'a', someList: ['test1'] }, foo { someString: 'b', someList: ['test1', 'test2'] }, fo

假设我有一门课
foo

class foo {
    String someString;
    List<String> someList;
}
将成为

arr2: [
    foo {
        someString: 'a',
        someList: ['test1']
    },
    foo {
        someString: 'b',
        someList: ['test1', 'test2']
    },
    foo {
        someString: 'c',
        someList: ['test2']
    },
]
现在,我有一个嵌套循环,它迭代每个foo的
someList
的每个元素,并将它们编译成一个映射,其中键是
someList
值,值是一组
someString
值,这些值来自存在
someList
值的foo。然后对条目集进行映射,将其转换为新的foos,并将键和值作为构造函数参数传递

Map<String, Set<String>> myMap;

for(foo f : arr1) {
    for(String s : f.someList) {
        Set<String> mySet = myMap.get(s);
        if(mySet == null) {
            myMap.put(s, new HashSet<String>(Arrays.asList(f.someString)));
        } else {
            mySet.add(f.someString);
        }
    }
}

List<String> myNewList = myMap.entrySet()
                              .stream()
                              .map(e -> 
                                    new foo(e.key, new ArrayList<String>(e.value)))
                              .collect(Collectors.toList());
Map-myMap;
对于(foo-f:arr1){
for(字符串s:f.someList){
设置mySet=myMap.get;
if(mySet==null){
put(s,新的HashSet(Arrays.asList(f.someString));
}否则{
add(f.someString);
}
}
}
List myNewList=myMap.entrySet()
.stream()
.map(e->
新foo(e.key,新ArrayList(e.value)))
.collect(Collectors.toList());

它似乎工作得很好,但它不是世界上最漂亮的,所以我想知道是否有其他方法可以做到这一点。

为什么不像这样在嵌套循环中创建foo对象呢

Map<String, foo> myMap;

 for(foo f : arr1) {
  for(String s : f.someList) {
    foo myFoo= myMap.get(s);
    if(mySet == null) {
        myFoo= new foo(s, new ArrayList<String>);
        myMap.put(s, myFoo);

    } 
    myFoo.somelist.add(f.someString);
  }
}
Map-myMap;
对于(foo-f:arr1){
for(字符串s:f.someList){
foo myFoo=myMap.get(s);
if(mySet==null){
myFoo=新foo(s,新数组列表);
myMap.put(s,myFoo);
} 
myFoo.somelist.add(f.someString);
}
}

以下是带有Guava库的java 8示例:

private static Function<Foo,Set<Foo>> fooStream(final Map<String,Foo> map){
        return foo -> foo.getSomeList().stream()
                .map(createNewFoo(foo.getSomeString(),map)).collect(Collectors.toSet());

    }

    private static Function<String,Foo> createNewFoo(final String someString,final Map<String,Foo> map){
        return s->{
            if(Objects.nonNull(map.get(s))){
                map.get(s).getSomeList().add(someString);
                return map.get(s);
            }
            return createNewFoo(s,someString,map);
        };
    }

    private static Foo createNewFoo(final String someListValue , final String someString,final Map<String,Foo> map){
        final Foo foo = new Foo(someListValue,Lists.newArrayList(someString));
        map.put(someListValue,foo);
        return foo;
    }
私有静态函数fooStream(最终映射){
返回foo->foo.getSomeList().stream()
.map(createNewFoo(foo.getSomeString(),map)).collect(Collectors.toSet());
}
私有静态函数createNewFoo(最终字符串someString,最终映射){
返回s->{
if(Objects.nonNull(map.get))){
map.get.getSomeList().add(someString);
返回地图。获取(s);
}
返回createNewFoo(s,someString,map);
};
}
私有静态Foo createNewFoo(最终字符串someListValue、最终字符串someString、最终映射){
final Foo Foo=new Foo(someListValue,Lists.newArrayList(someString));
map.put(someListValue,foo);
返回foo;
}
下面是如何在main方法中调用它:

final Map<String, Foo> myMap = Maps.newHashMap(); 
final Foo foo1 = new Foo("test1",Arrays.asList("A","B")); 
final Foo foo2 = new Foo("test2",Arrays.asList("B","C")); 
final List<Foo> foos = Arrays.asList(foo1,foo2); 
final Set<Foo> fooSet = foos.stream()
.map(fooStream(myMap)) 
.flatMap(Set::stream).collect(Collectors.toSet());
final Map myMap=Maps.newHashMap();
final Foo foo1=新的Foo(“test1”,Arrays.asList(“A”,“B”);
final Foo foo2=新的Foo(“test2”,Arrays.asList(“B”,“C”);
最终列表foos=Arrays.asList(foo1,foo2);
最终集fooSet=foos.stream()
.map(fooStream(myMap))
.flatMap(Set::stream).collect(collector.toSet());
其中Foo类是:

public class Foo {
    private String someString;
    private List<String> someList;

    public Foo(String someString, List<String> someList) {
        this.someString = someString;
        this.someList = someList;
    }
//getters and setters
}
公共类Foo{
私有字符串someString;
私人名单;
public Foo(String-someString,List-someslist){
this.someString=someString;
this.someList=someList;
}
//接球手和接球手
}

首先使用贴图翻转对象:

Map<String, Set<String>> map = new LinkedHashMap<>();
arr1.forEach(foo -> 
        foo.someList.forEach(s -> 
                map.computeIfAbsent(
                    s, 
                    k -> new LinkedHashSet<>())
                .add(foo.someString)));

这假设您有适当的构造函数。

基本上是在someList中重复。在理想情况下,我会将其切换为一个集合,但这是不可能的,因此我认为在最后将集合转换为列表要比每次遍历foo.someList要好。通常情况下,只需几点。1.您在
映射中的最终输出当前不是
列表
,而是
集合
。2.除非您最终创建自己的接口实现,否则
集合的初始化将无法以这种方式工作。3.初始化
Set mySet=myMap.get对于您希望获得的输出也没有意义。在某些地方,示例是伪代码,实际执行方法相当冗长。可能应该在最初的问题中明确说明这一点。我的想法是RE3需要进行空检查,初始化集合可以避免从if和else中的map中检索。哦,我想我明白你的意思了。只需执行包含键检查,而不是实际的init。编辑示例以使用实际语法。只需添加以澄清,然后适当的构造函数将字符串的
转换为对象中预期的
列表
。这很好,谢谢!这可能是个愚蠢的问题。LinkedHashSet只是为了维持顺序,还是有其他理由使用它?@AndrewRobie只是为了维持插入顺序。
Map<String, Set<String>> map = new LinkedHashMap<>();
arr1.forEach(foo -> 
        foo.someList.forEach(s -> 
                map.computeIfAbsent(
                    s, 
                    k -> new LinkedHashSet<>())
                .add(foo.someString)));
List<foo> result = new ArrayList<>();
map.forEach((k, v) -> list.add(new foo(k, new ArrayList<>(v))));