How to test for equality of Lists of String arrays

江枫思渺然 提交于 2021-02-11 08:10:37

问题


I think I can't see the forest for the trees... How do I test for equality (not identity) of all elements recursively in a List of String arrays? Here's a minimal example:

List<String[]> left = new ArrayList<>();
left.add(new String[]{"one", "two"});

List<String[]> right = new ArrayList<>();
right.add(new String[]{"one", "two"});

System.out.println(left.equals(right) ? "Yeah!" : "This is not what I want.");

I want to use this in unit tests.

A bit more context: I have a class that holds several fields, some of which are List of String arrays and some are Sets of String arrays. The class is a result of a parser (actually an intermediate step in a cascade of parsers). In order to test the parser I want to check for equality of instances of the class in question. The IDE-autogenerated equals implementation uses a cascade of Objects.equals invocations on the several List<String[]> and Set<String[]> fields, which is---so I figured---equivalent to the minimal example that I've provided above.


回答1:


The Java documentation requires list equals() to behave as you're using it, so your code would work if these were Lists of Lists:

boolean equals(Object o)

Compares the specified object with this list for equality. Returns true if and only if the specified object is also a list, both lists have the same size, and all corresponding pairs of elements in the two lists are equal. (Two elements e1 and e2 are equal if (e1==null ? e2==null : e1.equals(e2)).) In other words, two lists are defined to be equal if they contain the same elements in the same order. This definition ensures that the equals method works properly across different implementations of the List interface.

However at the "leaves" you have plain Java arrays. These will use the Object definition of equals, which tests for reference identity, not value equality.

One way around this in your tests is to write a little helper factory routine that accepts a variable argument list of Strings and produces List returns to replace the Java arrays you're currently using. Then all ought to work fine. Your example would look like this:

// A little helper to avoid the awkward syntax
// Arrays.asList(new String [] { "one", "two" })
public static List<String> listOf(String ... strings) {
    return Arrays.asList(strings);
}

public static void main(String[] args) {
    List<List<String>> left = new ArrayList<>();
    left.add(listOf("one", "two"));

    List<List<String>> right = new ArrayList<>();
    right.add(listOf("one", "two"));

    System.out.println(left.equals(right) ? "Yeah!" : "This is not what I want.");
}



回答2:


Test that both lists have the same size. Then if they do, iterate on each of them, and compare each pair of arrays using Arrays.equals().

It would be easier if you had a List of lists instead (List<List<String>>), because lists can be compared using equals() directly.




回答3:


import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.swing.text.html.HTMLDocument.Iterator;


public class test 
{
  public static void main(String args[])
  {

      List<String[]> left = new ArrayList<String[]>();
      left.add(new String[]{"one", "two"});

      List<String[]> right = new ArrayList<String[]>();
      right.add(new String[]{"one", "two"});

      java.util.Iterator<String[]> leftIterator =left.iterator();
      java.util.Iterator<String[]> rightIterator =right.iterator();
      if(left.size() !=right.size())   System.out.println("not equal");
      for(;leftIterator.hasNext();)
      {
         if(Arrays.equals(leftIterator.next(), rightIterator.next())) continue;
         else
         {
             System.out.print("not equal");
             break;
         }
      }


  }
}



回答4:


You want to compare each list, keep track of if they are equal using a boolean. I'm not aware of a single function that will do this directly for you.

    List<String[]> left = new ArrayList<>();
    left.add(new String[]{"one", "two"});

    List<String[]> right = new ArrayList<>();
    right.add(new String[]{"one", "two"});

    boolean isEqual = true;
    if (left.size() == right.size())
    {
        // Test for equality
        for (int i = 0; i < left.size(); i++)
        {
            // Compare each array in the list
            if (!Arrays.equals(leftArray, rightArray))
            {
                isEqual = false;
                break;
            }
        }
    }
    else
    {
        // The two list are not even the same length, so are not equal.
        isEqual = false;
    }

    System.out.println(isEqual ? "Yeah!" : "This is not what I want.");



回答5:


Thanks to everyone for your input. This is my resulting code.

protected static boolean equalsCollectionOfArrays(Collection<? extends Object[]> leftCollection,
                                                   Collection<? extends Object[]> rightCollection) {
    if (leftCollection.size() != rightCollection.size()) {
        return false;
    } else {
        Iterator<? extends Object[]> left = leftCollection.iterator();
        Iterator<? extends Object[]> right = rightCollection.iterator();
        while (left.hasNext()) {
            if (!Arrays.equals(left.next(), right.next())) {
                return false;
            }
        }
        return true;
    }
}

protected static int hashCodeCollectionOfArrays(Collection<? extends Object[]> collection) {
    int hash = 3;
    for (Object[] objects : collection) {
        hash = 67 * hash + Arrays.hashCode(objects);
    }
    return hash;
}

It turned out that my problem was not limited to List<String[]>, but that I ran into the same issues with Set<String[]> and also hashCode(). I've ended up with these two methods that I've incorporated into the class' equals and hashCode implementation. The generic wildcard is not necessary (there are only String arrays), but I just wanted to check out my understanding of generics by the way when I am learning a basic lesson.

I am considering to avoid arrays in the future. Any comments are very welcome.




回答6:


If you need to compare lists, try using equals() of that particular list instance providing another one to compare to.

If you need to compare arrays, try using Arrays.equals().

If you are doing this in test methods org.junit.Assert's assertArrayEquals() or assertEquals() should od as they will call those methods behind the covers.



来源:https://stackoverflow.com/questions/21365422/how-to-test-for-equality-of-lists-of-string-arrays

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!