简体   繁体   中英

contains() method not working

private List<String> values = new ArrayList<String>();

public WhitespaceEqualsTest() {
    values.add("I ");
    values.add("I");
    values.add(". ");
    values.add(".");
    values.add("1");
    values.add("1 ");

    System.out.println(refine(values));
}

private List<String> refine(List<String> input){
    ArrayList<String> outerLoopValues = (ArrayList<String>) input;
    ArrayList<String> innerLoopValues = (ArrayList<String>) input;
    ArrayList<String> results = new ArrayList<String>();

    for(String string1 : outerLoopValues){
        for(String string2 : innerLoopValues){
            if(string1.contains(string2) == false){
                results.add(string1);
            }
        }
    }

    Set<String> temp = new HashSet<String>();
    temp.addAll(results);
    results.clear();
    results.addAll(temp);

    return results;
}
@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((values == null) ? 0 : values.hashCode());
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    WhitespaceEqualsTest other = (WhitespaceEqualsTest) obj;
    if (values == null) {
        if (other.values != null)
            return false;
    } else if (!values.equals(other.values))
        return false;
    return true;
}

I've overriden the hashCode() and equals() , so I'm not really sure what's wrong. They are generated using Eclipse (Source -> Generate hashCode() and equals()). Why isn't it detecting that the same character without a space is contained within a character with a space? The output is:

[1, . , I , I, ., 1 ]

As mentioned in one of the comments, you should be using a String wrapper to wrap the strings and override the equals and hashcode methods.

My solution is based on the assumption that "I " should be equals to "I" , hence only one of them should be added into the result.

However I'll need to addon that based on the documentation in Java Objects and Java Arraylist with regards to equals and contains implementation respectively. The hashcode method would have to return a common value. I've written the explanation in the code as comments. Let me know if there are any issues.

Main Class

public class StackOverflowMain
{
    private static List<String> values = new ArrayList<String>();

    public static void main(String[] args) {

        values.add("I ");
        values.add("I");
        values.add(". ");
        values.add(".");
        values.add("1");
        values.add("1 ");
        List<WhitespaceEqualsTest> toRefineList = new ArrayList<WhitespaceEqualsTest>();
        for (String value : values) {
            toRefineList.add(new WhitespaceEqualsTest(value));
        }

        System.out.println(refine(toRefineList));
    }

    private static List<WhitespaceEqualsTest> refine(List<WhitespaceEqualsTest> input) {
        ArrayList<WhitespaceEqualsTest> loopValues = (ArrayList<WhitespaceEqualsTest>) input;
        ArrayList<WhitespaceEqualsTest> results = new ArrayList<WhitespaceEqualsTest>();

        for (WhitespaceEqualsTest value : loopValues) {
            if (!results.contains(loopValues)) {
                results.add(value);
            }
        }

        Set<WhitespaceEqualsTest> temp = new HashSet<WhitespaceEqualsTest>();
        temp.addAll(results);
        results.clear();
        results.addAll(temp);

        return results;

    }
}

Inner WhitespaceEqualsTest Class

class WhitespaceEqualsTest {
    private String value;

    public WhitespaceEqualsTest(String value) {
        this.value = value;
    }

    public void setString(String value) {
        this.value = value;
    }

    public String getString() {
        return this.value;
    }

    public int hashCode() {
        /*
         * Arraylist.contains is evaluated by using (o==null ? e==null : o.equals(e)) as mentioned in the javadoc
         * and Object.equals() would evaluate using hashcode() first to check if the object o is equal to object e
         * before calling .equals() method to evaluate.
         * 
         * As mentioned in java doc at http://docs.oracle.com/javase/7/docs/api/java/util/Collection.html#equals(java.lang.Object)
         * c1.equals(c2) implies that c1.hashCode()==c2.hashCode() should be satisfied
         * which is not in this question
         */      
        return 0;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        WhitespaceEqualsTest other = (WhitespaceEqualsTest) obj;
        if (value == null) {
            if (other.value != null)
                return false;
        } else if (!value.contains(other.value) && !other.value.contains(value)){ 
            /*
             * Does a checking on both ends since "I " contains "I" but "I" does not contain "I " due to the whitespace
             * For this question, if one of the condition satisfy it should be equal
             */
            return false;
        }           
        return true;
    }

    @Override
    public String toString() {
        return this.value;
    }
}

Result

[I , . , 1]

String class is final. So you cannot override its equals and hashCode methods.

private List<StringWrapper> values = new ArrayList<StringWrapper>();

public WhitespaceEqualsTest() {
    values.add(new StringWrapper("I "));
    values.add(new StringWrapper("I"));
    values.add(new StringWrapper(". "));
    values.add(new StringWrapper("."));
    values.add(new StringWrapper("1"));
    values.add(new StringWrapper("1 "));

    System.out.println(refine(values));
}

private List<StringWrapper> refine(List<StringWrapper> input){
    //no need to iterate the list
    //the set will automatically cancel out the duplicate
    Set<StringWrapper> temp = new HashSet<StringWrapper>(input);

    ArrayList<StringWrapper> results = new ArrayList<StringWrapper>();
    results.addAll(temp);
    return results;
}

Create a wrapper class of String then override the equals and hashcode method.

class StringWrapper {
    private String value;

    public StringWrapper(String value){
        this.value = value;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
    @Override
    public String toString(){
        return value;
    }
    @Override
    public boolean equals(Object obj){
        boolean result = Boolean.FALSE;
        if(obj != null && obj instanceof StringWrapper){
            StringWrapper stringWrapper = (StringWrapper) obj;
            result = value.trim().equals(stringWrapper.getValue().trim());
        }
        return result;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((value.trim() == null) ? 0 : value.trim().hashCode());
        return result;
    }
}

You add the values to a Set. In a Set in any case a value occurs once - hence it is a set. ;)

You might as well modify the loop to see what happens

for(String string1 : outerLoopValues){
            for(String string2 : innerLoopValues){
                if(string1.contains(string2) == false){
                    results.add(string1);
                    System.out.println("added \"" + string1 + "\" since it does not contain \"" + string2 + "\"");
                }
            }
        }

Giving the following output:

added "I " since it does  not contain ". "
added "I " since it does  not contain "."
added "I " since it does  not contain "1"
added "I " since it does  not contain "1 "
added "I" since it does  not contain "I "
added "I" since it does  not contain ". "
added "I" since it does  not contain "."
added "I" since it does  not contain "1"
added "I" since it does  not contain "1 "
......
[1, . , I , I, ., 1 ]

To add them if they do not contain each other is the idea i guess?

Then pushing the List through a Set removes the duplicates! See here: Does adding a duplicate value to a HashSet/HashMap replace the previous value

Changing the condition in the Loop from false to true yields this (no change after using the Set/HashSet in the last line of output!)

added "I " since it does contain "I "
added "I " since it does contain "I"
added "I" since it does contain "I"
added ". " since it does contain ". "
added ". " since it does contain "."
added "." since it does contain "."
added "1" since it does contain "1"
added "1 " since it does contain "1"
added "1 " since it does contain "1 "
[1, . , I , I, ., 1 ]

Which answers your question: It does detect if eg "I " contains "I".

System.out.println("I ".contains("I"));

says "true"

Hope this helps ^^-d

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM