收集removeAll无视案例?

use*_*786 12 java collections case-insensitive hashset

好的,这是我的问题.我必须这样做HashSet,我使用该removeAll方法删除一个集合中存在的值.

在调用方法之前,我显然将值添加到Sets中.我在添加之前调用.toUpperCase()每个String,因为两个列表中的值都是不同的情况.这个案子没有押韵或理由.

一旦我打电话removeAll,我需要将原始案例返回给剩下的值Set.有没有一种有效的方法可以在不运行原始列表和使用的情况下执行此操作CompareToIgnoreCase

例:

列表1:

"BOB"
"Joe"
"john"
"MARK"
"dave"
"Bill"
Run Code Online (Sandbox Code Playgroud)

列表2:

"JOE"
"MARK"
"DAVE"
Run Code Online (Sandbox Code Playgroud)

在此之后,HashSet使用toUpperCase()on 为每个List 创建一个单独String的.然后打电话removeAll.

Set1.removeAll(set2);

Set1:
    "BOB"
    "JOHN"
    "BILL"
Run Code Online (Sandbox Code Playgroud)

我需要让列表再次看起来像这样:

"BOB"
"john"
"Bill"
Run Code Online (Sandbox Code Playgroud)

任何想法将不胜感激.我知道它很差,应该有原始列表的标准,但这不是我要决定的.

McD*_*ell 13

在我原来的回答中,我不假思索地建议使用a Comparator,但这会导致TreeSet违反equals合同并且是一个等待发生的错误:

// Don't do this:
Set<String> setA = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
setA.add("hello");
setA.add("Hello");
System.out.println(setA);

Set<String> setB = new HashSet<String>();
setB.add("HELLO");
// Bad code; violates symmetry requirement
System.out.println(setB.equals(setA) == setA.equals(setB));
Run Code Online (Sandbox Code Playgroud)

最好使用专用类型:

public final class CaselessString {
  private final String string;
  private final String normalized;

  private CaselessString(String string, Locale locale) {
    this.string = string;
    normalized = string.toUpperCase(locale);
  }

  @Override public String toString() { return string; }

  @Override public int hashCode() { return normalized.hashCode(); }

  @Override public boolean equals(Object obj) {
    if (obj instanceof CaselessString) {
      return ((CaselessString) obj).normalized.equals(normalized);
    }
    return false;
  }

  public static CaselessString as(String s, Locale locale) {
    return new CaselessString(s, locale);
  }

  public static CaselessString as(String s) {
    return as(s, Locale.ENGLISH);
  }

  // TODO: probably best to implement CharSequence for convenience
}
Run Code Online (Sandbox Code Playgroud)

此代码不太可能导致错误:

Set<CaselessString> set1 = new HashSet<CaselessString>();
set1.add(CaselessString.as("Hello"));
set1.add(CaselessString.as("HELLO"));

Set<CaselessString> set2 = new HashSet<CaselessString>();
set2.add(CaselessString.as("hello"));

System.out.println("1: " + set1);
System.out.println("2: " + set2);
System.out.println("equals: " + set1.equals(set2));
Run Code Online (Sandbox Code Playgroud)

不幸的是,这更加冗长.

  • 无需滚动自己的比较器.String类为您提供了一个:http://java.sun.com/javase/6/docs/api/java/lang/String.html#CASE_INSENSITIVE_ORDER (4认同)