Переключить направление ассоциации между объектами - PullRequest
0 голосов
/ 08 ноября 2018

Скажите, у меня есть класс foo:

class foo {
    String someString;
    List<String> someList;
}

Если у меня есть список foo, есть ли способ для меня создать новый список / массив / что угодно из foo с переназначенными значениями someString и someList? Например:

arr1: [
    foo {
        someString: 'test1',
        someList: ['a', 'b']
    },
    foo {
        someString: 'test2',
        someList: ['b', 'c']
    }
]

станет

arr2: [
    foo {
        someString: 'a',
        someList: ['test1']
    },
    foo {
        someString: 'b',
        someList: ['test1', 'test2']
    },
    foo {
        someString: 'c',
        someList: ['test2']
    },
]

Прямо сейчас у меня есть вложенный цикл, который перебирает каждый элемент someList для каждого foo и компилирует их в карту, где ключом является значение someList, а значением является набор значений someString которые пришли из foos, где присутствовало значение someList. Затем создайте карту набора записей, чтобы преобразовать ее в новые 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());

Кажется, что он работает нормально, но он не самый красивый в мире, поэтому мне было интересно, есть ли другой подход к этому.

Ответы [ 3 ]

0 голосов
/ 08 ноября 2018

Вот пример на java 8 с библиотекой Guava:

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;
    }

А вот как это можно назвать в основном методе:

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());

Где класс 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
}
0 голосов
/ 08 ноября 2018

Сначала переверните ваши объекты, используя карту:

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

Затем создайте foo объекты с карты:

List<foo> result = new ArrayList<>();
map.forEach((k, v) -> list.add(new foo(k, new ArrayList<>(v))));

Предполагается, что у вас есть соответствующий конструктор.

0 голосов
/ 08 ноября 2018

Почему бы не создать объекты 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);
  }
}
...