简体   繁体   中英

Checking containment in a Set of strings in Java

I have a Set of String[]. I want to check whether this Set contains another String[].

Set<String[]> s  = new HashSet<String[]>();
s.add(new String[] {"lucy", "simon"});
System.out.println(s.contains(new String[] {"lucy", "simon"}));

However, false is printed. My guess is this is because only the references are being compared and not the actual Strings. It seems, the only option I have is to create a class, say Phrase, and implement hashCode() and equals() (that use Arrays.hashCode(...) ).

Is there any other way to achieve what I want?

Your guess is correct: arrays ([]) do not implement a deep equals method: they are equals if they are the same instance.

The simplest solution would be: replacing String[] by List<String>

An other way (but i do not recommend it) is to implement your own Set, which does not based on Object.equals but on java.util.Arrays.equals(Object[]a, Object[]b)

Convert that String[] to List<String> and it should work out pretty well.

Set<List<String>> s  = new HashSet<List<String>>();
s.add(Arrays.asList("lucy", "simon"));
System.out.println(s.contains(Arrays.asList("lucy", "simon")));

Can the elements of the String[] be in different orders and still make the whole array be considered equal to another array containing the same elements in another order? If yes, you'd indeed be better off implementing a container class and overriding equals and hashcode.

if not, and if storing the internal elements as Lists instead of arrays is an acceptable alternative, then you could do this:

package com.stackoverflow;


import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;


public class StringContainment {

  public static void main(final String[] args) {
    final Set<String[]> s = new HashSet<String[]>();
    final Set<List<String>> s2 = new HashSet<List<String>>();

    s.add(new String[] {"lucy", "simon"});
    s2.add(Arrays.asList(new String[] { "lucy", "simon" }));

    System.out.println(s.contains(new String[] {"lucy", "simon"})); // false
    System.out.println(s2.contains(Arrays.asList(new String[] {"lucy", "simon"}))); // true
  }

}

The first check will return false, the second true. Might be easier that way if you can use lists.

If you can't, you could still use this as long as you don't need to do this comparison too often (it's definitely not a good idea performance-wise).

Use Set<Set<String>> or Set<List<String>> instead of Set<String[]>

Code:

List<String> s1=Arrays.asList("1","2"),s2=Arrays.asList("1","2");
System.out.println(s1.equals(s2) + " "+s1.hashCode()+ " "+s2.hashCode());

Output:

true 2530 2530

Sounds like you've already answered your question. One option is as you already stated. The another would be to use Set> , since the API for equals(Object) says:

Compares the specified object with this collection for equality.

I'd just loop through and call Arrays.equals:

something like this:

boolean contains(Set<String[]> s, String[] item) {
  for(String[] toCompare: s) {
    if(Arrays.equals(toCompare, item)) {
        return true;
    }
  }
  return false;
}

not sure if it's the fastest but it should do the job nicely

With Java8 stream introduction you can do it the following way:

Boolean res = s.stream()
  .anyMatch(elm -> elm.equals("lucy") || elm.equals("simon"));

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