2

Lets assume I have a list List<Foo> mylist = parseFromCSV();

Where

parseFromCSV() 

returns a list of object of Foo class. Foo class has her private attributes:

private mailId;
private status;

... getters and setters...

A Possibly pair of objects in

mylist: [{MailId=100, Status=BOUNCED, [email protected]},{MailId=100, Status=OPENED, [email protected]}, {MailId=200, Status=CLICKED, EMAIL = [email protected]}, {MailId=100, Status=HARDBOUNCED, EMAIL = [email protected]}]

I can indeed have duplicates in my list because the objects listed represents the CSV lines parsed into Java Objects. Each MailId has multiple different possible status of feedback.

What I am interested in, is to retrieve only the "important" status in my set of possible statuses for one MailId and persist into my database.

OPENED > CLICKED > HARDBOUNCED > BOUNCED (priority of the statuses).

In my example: for MailId= 100 I will only persist the OPENED status into my status column in database.

What will be a good way of achieving this? Should I create a new List (Set?) containing each pair filtered of {MailId, Status(Prioritized)}, ... {MailIdN, StatusN(Prioritized)...} ? Can we add priority on String using Enumerations or making a new comparator for my objects of class Foo?

The persisting operations into mysql database using hibernate should look like this:

persistStatusIntoTable(String MailId, String Status(Taken only status based on priority))

Thanks to all of your help !

3
  • 2
    I'd suggest putting the status as its own separate class which has a private int priority (or something like that), using a custom Comparator<String> would also work, but may be quite hard to make if you add more statusses. (In some weird scenario.) Then create a new List and add all elements from myList to it that pass your status priority condition. Commented Mar 22, 2017 at 23:40
  • I think it will be a bad idea to make it into a separate class since the status represent a field of my Entity class FeedBackReceived . I think I should go on making a custom Comparator<String> like you said. The possible statuses I can have are all set to those I mention. The comparator will be generic and applied for other existing Lists with different type of Objects that include also statuses. I have List<foo>, List<Bar>, List<FooBar> representing different email Accounts Commented Mar 22, 2017 at 23:58
  • Thanks to both for your answers and time. @Dolev what do you mean with tables? database tables? Commented Mar 23, 2017 at 0:04

2 Answers 2

2

If you don't want to use 3rd party libraries and don't want to use an enum class:

// initialization which you will have to do once somewhere in your code
List<String> ordering = Arrays.asList("OPENED", "CLICKED", "HARDBOUNCED", "BOUNCED");
Map<String, Integer> priorityMap = IntStream.range(0, ordering.size()).boxed()
        .collect(Collectors.toMap(ordering::get, i -> i));

// example input
List<Foo> myList = Arrays.asList(
        new Foo("100", "BOUNCED"), new Foo("100", "OPENED"),
        new Foo("101", "BOUNCED"), new Foo("101", "HARDBOUNCED"), new Foo("101", "BOUNCED"));

// determine foo objects that should be persisted 
Collection<Foo> toBePersisted = myList.stream()
        .filter(t -> priorityMap.containsKey(t.getStatus()))
        .collect(Collectors.toMap(Foo::getMailId, t -> t,
                BinaryOperator.minBy(Comparator.comparing(t -> priorityMap.get(t.getStatus())))))
        .values();

What this code does is:

  • set up a map which maps status to priority (lower int = higher priority)
  • filter Foo instances that have an invalid status
  • group Foo instances by mailId
  • keep Foo instance with minimum priority integer (= highest priority) per group
  • get values of resulting map
Sign up to request clarification or add additional context in comments.

Comments

2

I assume a couple of things here (that could be easily changed). First Status is an enum (but you could do the same for a String for example).

Then I'm using google guava Ordering to simplify building the Comparator (you could do this without it).

 Comparator<Status> c = Ordering.explicit(
            ImmutableList.of(Status.OPENED, Status.CLICKED, Status.HARDBOUNCED, Status.BOUNCED));

    List<Foo> list = Stream.of(new Foo(Status.BOUNCED, 57), new Foo(Status.OPENED, 57),
            new Foo(Status.CLICKED, 58), new Foo(Status.BOUNCED, 57),
            new Foo(Status.HARDBOUNCED, 58))
            .collect(Collectors.groupingBy(Foo::getId,
                    Collectors.mapping(Foo::getStatus, Collectors.toCollection(() -> new PriorityQueue<>(c)))))
            .entrySet()
            .stream()
            .map(e -> new Foo(e.getValue().remove(), e.getKey()))
            .collect(Collectors.toList());

    System.out.println(list); // [id = 57 status = OPENED, id = 58 status = CLICKED]

The idea is to create a Comparator that defines the order of your Statuses; then use that comparator to populate a PriorityQueue (for some id); ultimately I am only interested in the first one - the most important as you call it (and that is the first according to the Comparator).

And here is the version that uses a String versus an enum for Status:

 Comparator<String> c = Ordering.explicit(
            ImmutableList.of("OPENED", "CLICKED", "HARDBOUNCED", "BOUNCED"));

    List<Foo> list = Stream.of(new Foo("BOUNCED", 57), new Foo("OPENED", 57),
            new Foo("CLICKED", 58), new Foo("BOUNCED", 57),
            new Foo("HARDBOUNCED", 58))
            .collect(Collectors.groupingBy(Foo::getId,
                    Collectors.mapping(Foo::getStatus, Collectors.toCollection(() -> new PriorityQueue<>(c)))))
            .entrySet()
            .stream()
            .map(e -> new Foo(e.getValue().remove(), e.getKey()))
            .collect(Collectors.toList());

1 Comment

Lot of thanks your solution is for no doubt correct and solve my problem however I checkmarked the above answer since it does not require any 3rd library and in my case I don't want to use on. I am sure it will help somebody else in the future! But thank you again !

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.