1

I have List of log events that I shoud check, that they are the same as should be. There is structure of Event object:

public class Event {
    public String type;
    public List<Item> items;

    public Event(String type, List<Item> items) {
        this.type = type;
        this.items = items;
    }
}
public class Item {
    public String id;
    public String value;

    public Item(String id, String value) {
        this.id = id;
        this.value = value;
    }
}

Lets fill "should" object, "real" object and check that they have same items

List<Event> should = asList(
                new Event("1000", asList(new Item("server_id", "1"), new Item("user_id", "11"))),
                new Event("1000", asList(new Item("server_id", "1"), new Item("user_id", "11"))));
        List<Event> logged = asList(
                new Event("1000", asList(new Item("server_id", "1"), new Item("user_id", "11"))),
                new Event("1000", asList(new Item("server_id", "1"), new Item("user_id", "11"))));
        boolean logMatch = logged.stream()
                                    .allMatch(e1 ->
                                            should.stream()
                                                      .allMatch(e2 -> e2.items
                                                                        .stream()
                                                                        .allMatch(a2 -> e1.items
                                                                                          .stream()
                                                                                          .anyMatch(a1 -> a1.value.equals(a2.value)))));
        System.out.println(logMatch);

It's true, but I have an issue, if I change any value of "should" to "11", I'll get true. How can I fix this or how to make this comparison simpler?

Stefan Zobel
  • 3,182
  • 7
  • 28
  • 38
callmedope
  • 83
  • 1
  • 9
  • Are you checking that all `value` fields are equal on an item-to-item basis? – ernest_k Oct 19 '18 at 09:21
  • @ernest_k i want to check that every Event from one list has same in another list. Events will be same if there id/value of all items will be the same. And i totally broke my brain when i tried to write this:) – callmedope Oct 19 '18 at 09:25

1 Answers1

3

Your problem is that you're just checking that each logged element has at least an element in the should list with which it has the same value. You rather want to check that the two value collections are equivalent.

A simple correction can use list comparison in this case:

List<String> actualValues =  logged.stream().flatMap(l -> l.items.stream())
        .map(i -> i.value).collect(Collectors.toList());
List<String> shouldValues = should.stream().flatMap(l -> l.items.stream())
        .map(i -> i.value).collect(Collectors.toList());

boolean logMatch = actualValues.equals(shouldValues);

This comparison is strict and takes order into account. If you'd rather ignore the order of elements, you can collect to set to ignore the order of items.


EDIT: You can compare actual events if you need to check multiple fields. The following uses a predicate:

List<Item> actualValues =  logged.stream().flatMap(l -> l.items.stream())
        .collect(Collectors.toList());
List<Item> shouldValues = should.stream().flatMap(l -> l.items.stream())
        .collect(Collectors.toList());

BiPredicate<Item, Item> predicate = (item1, item2) -> item1.id.equals(item2.id) 
        && item1.value.equals(item2.value);

boolean res = actualValues.size() == shouldValues.size() //should be same length
        && IntStream.range(0, actualValues.size())
        .filter(i -> !predicate.test(actualValues.get(i), shouldValues.get(i)))
        .count() == 0; //all elements's ID and value must match
ernest_k
  • 44,416
  • 5
  • 53
  • 99