0

I have list of Objects say

class Address {

  private String houseno;
  private String street;
  private String city;
  private String landmark;
  private String country;
}

class Obj1 {
  private String id;
  private String name;
  private String mail;
  private List<Address> address;
}

List<Obj1> obj1s = new ArrayList<>();

I have list of obj1s filled with data where I need to extract it with some filters. I need to retrieve all the obj1s where city and country must not be duplicate. If either of the address list contains same city and country which is same in other obj1, then I don't need in that list.

I am trying the same but not working.

obj1s.stream().collect(Collectors.toMap((obj1.getAddress()), p -> p, (p, q) -> p)).values();

It can be done with loops and if else conditions, but looking for java streams and betters solutions. Is there any good way to solve this?

city+country can be duplicate across all obj1s. In address list, it will be unique

5
  • 1
    If city+country is duplicated across all Obj1s in obj1s, or across all addresses in the Obj1 object? Commented May 5, 2021 at 16:47
  • @ernest_k, It can be duplicated across obj1s Commented May 5, 2021 at 16:54
  • Aside: The question would start making more sense if you rename Obj1 to User. Doubt: If for Obj1 a and Obj1 b any of their Address has same city+country, you don't want these two to be a part of final result? Commented May 5, 2021 at 17:07
  • @Naman, I want one to be part of result, not the duplicate one Commented May 5, 2021 at 17:09
  • 2
    To be clear of the input and desired output, it would be great to share your approach with the loops and conditions you have achieved as you said. Commented May 5, 2021 at 17:13

2 Answers 2

1

We need something like "distinct" which is kind of like a stateful filter. So we can create our own filter having its own state of previously seen pairs of cities/countries. This can be achieved with having a filter with its own Set:

public static <T> Predicate<T> distinctAddress() {
    Set<Object> seen = ConcurrentHashMap.newKeySet();
    return t -> {
        boolean r = ((Obj1)t).getAddress().stream().map((a) -> seen.contains(new AbstractMap.SimpleImmutableEntry<>(a.getCity(), a.getCountry()))).anyMatch((b) -> b);
        ((Obj1)t).getAddress().stream().forEach((a) -> seen.add(new AbstractMap.SimpleImmutableEntry<>(a.getCity(), a.getCountry())));
        return !r;
    };
}

List<Obj1> list = obj1s.stream().filter(distinctAddress()).collect(Collectors.toList());

Edit: I just realized you mention an address will always be unique inside an address list. In that case you can shorten the Predicate as so (as you wouldn't already have it in the Set because of the same list):

public static <T> Predicate<T> distinctAddress() {
    Set<Object> seen = ConcurrentHashMap.newKeySet();
    return t -> ((Obj1)t).getAddress().stream().map((a) -> seen.add(new AbstractMap.SimpleImmutableEntry<>(a.getCity(), a.getCountry()))).filter((e) -> e).count() > 0;
}

List<Obj1> list = obj1s.stream().filter(distinctAddress()).collect(Collectors.toList());
Sign up to request clarification or add additional context in comments.

Comments

1

You can do like this:

Map<String, List<Obj1>> result= objs.stream()
            .flatMap(obj -> {

                        Map<String, Obj1> map = obj.address.stream()
                                .map(address -> address.country + address.city)
                                .collect(Collectors.toMap(String::valueOf, str -> obj));

                        return map.entrySet().stream();
                    }

            ).collect(Collectors.groupingBy(
                    Map.Entry::getKey,
                    Collectors.mapping(Map.Entry::getValue, Collectors.toList()))
            );

It returs a map which it's key is generated for each address by address.name and address.country , and it's value is a list of Obj1 objects that currently have this address.

Please make sure each list of addresses has unique elements before testing.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.