Search code examples
javaassertmatcherhamcrest

Assert List<List<String>> contains List<String> with no order


I have a List<List<String>> with sample data like:

("T1#R1", "T1#R1", "T1#R3", "T1#R4")
("T1#R1", "T1#R1", "T1#R3", "T1#R5")
("T1#R1", "T1#R1", "T1#R6", "T1#R4")
("T1#R1", "T1#R1", "T1#R6", "T1#R5")

And I need to assert, that a List<String> is present in the above sample, but without taking order into consideration.

For example, the following list ("T1#R1", "T1#R1", "T1#R4", "T1#R3") should be considered as present in the List<List<String>>, as it would contain the same items as the 1st list, but in different order.

On the other hand, ("T1#R1", "T1#R3", "T1#R4", "T1#R3") shouldn't be considered as present in the list, as it has the same items, but with a different count.

I know I could do this programmatically, but was wandering if there could be a Matcher for example that could help.

I've seen assertions like:

assertThat(myList, containsInAnyOrder(anotherList.toArray())

But that would just compare one list with another, and not a list inside a List of Lists.

PS: I'm using Java6, hamcrest-core-1.3, testng-5.14.1


Solution

  • I don't know of any matcher that can do what you want, so I'm afraid you'll have to program it.

    I would simply sort the target list and then I'd iterate the sublists until a match is found:

    List<String> target = new ArrayList<>(anotherList);
    target.sort();
    
    boolean result = myList.stream()
        .anyMatch(sublist -> equalsInAnyOrder(sublist, target));
    

    Where method equalsInAnyOrder would be as follows:

    public <T> boolean equalsInAnyOrder(List<T> sublist, List<T> target) {
    
        List<String> copy = new ArrayList<>(sublist);
        copy.sort();
    
        return copy.equals(target);
    }
    

    This sorts each sublist and compares it with the target sorted list, so it's not performance-wise, but at least it's simple and succint code.


    EDIT as per OP's need to target Java 6:

    The logic is exactly the same as in the Java 8 version. First sort the target list and then compare each sublist until a match is found:

    List<String> target = new ArrayList<>(anotherList);
    Collections.sort(target);
    

    The stream() with anyMatch has now become a while loop:

    boolean match = false;
    Iterator<List<String>> it = myList.iterator();
    while (it.hasNext() && !match) {
        List<String> sublist = it.next();
        match = equalsInAnyOrder(sublist, target);
    }
    

    And now method equalsInAnyOrder looks like this:

    public <T> boolean equalsInAnyOrder(List<T> sublist, List<T> target) {
    
        List<String> copy = new ArrayList<>(sublist);
        Collections.sort(copy);
    
        return copy.equals(target);
    }