Набор removeAll игнорирующий регистра?

У Magnus есть он правильный, но нужно также отметить, что на большинстве языков (pre-C), условное выражение конец критерий (т.е. "останавливаются, когда я равняюсь 100"). В C (и большинство постязыков C), это эти , продолжаются критерий (т.е. "продолжаются, в то время как я - меньше чем 100").

12
задан Nicolas Filotto 2 February 2017 в 14:28
поделиться

4 ответа

В моем первоначальном ответе я бездумно предложил использовать Компаратор , но это приводит к тому, что TreeSet нарушает контракт равно , и это ошибка, ожидающая своего появления:

// 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));

Лучше использовать специальный тип:

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
}

Этот код с меньшей вероятностью вызовет ошибки:

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));

Это, к сожалению, более подробный вариант.

13
ответ дан 2 December 2019 в 19:32
поделиться

Вы можете использовать хэш-карту и использовать набор заглавных букв в качестве ключей, которые сопоставляются со смешанным набором регистров.

Ключи хэш-карт уникальны, и вы можете получить набор из них с использованием HashMap.keyset ();

для получения исходного регистра, это так же просто, как HashMap.get ("UPPERCASENAME").

И согласно документации :

Returns установленный вид ключей содержится на этой карте. Набор поддерживаются картой, поэтому изменения в карта отражается в наборе, а наоборот. Набор поддерживает элемент удаление, которое удаляет соответствующее отображение с этой карты, через Iterator.remove, Set.remove, removeAll, keepAll и очистить операции. Он не поддерживает операции add или addAll.

Итак, HashMap.keyset (). removeAll повлияет на хэш-карту :)

РЕДАКТИРОВАТЬ: используйте решение Макдауэлла. Я упустил из виду тот факт, что вам не нужно, чтобы буквы были прописными: P

1
ответ дан 2 December 2019 в 19:32
поделиться

Насколько мне известно, hashset использует метод hashCode объекта, чтобы отличать их друг от друга. поэтому вам следует переопределить этот метод в своем объекте, чтобы различать случаи.

если вы действительно используете строку, вы не можете переопределить этот метод, так как вы не можете расширить класс String.

поэтому вам нужно создать свой собственный класс, содержащий строку в качестве атрибута, который вы заполняете своим содержимым. вы можете захотеть иметь методы getValue () и setValue (String) для изменения строки.

тогда вы можете добавить свой собственный класс в хэш-карту.

это должно решить вашу проблему.

с уважением

0
ответ дан 2 December 2019 в 19:32
поделиться

Это было бы интересно решить с помощью google-коллекций . Можно было бы иметь константу Predicate вида:

private static final Function<String, String> TO_UPPER = new Function<String, String>() {
    public String apply(String input) {
       return input.toUpperCase();
}

и тогда то, что вам нужно, можно было бы сделать что-то вроде этого:

Collection<String> toRemove = Collections2.transform(list2, TO_UPPER);

Set<String> kept = Sets.filter(list1, new Predicate<String>() {
    public boolean apply(String input) {
        return !toRemove.contains(input.toUpperCase());
    }
}

То есть:

  • Построить версию только для верхней части списка 'отбрасывать'
  • Применить фильтр к исходному списку, сохранив только те пункты, чье прописное значение составляет а не в списке только для верхней части списка.

Обратите внимание, что вывод Collections2.transform не является эффективной реализацией Set, поэтому, если вы имеете дело с большим количеством данных и стоимость исследования этого списка причинит вам боль, вы можете вместо этого использовать

Set<String> toRemove = Sets.newHashSet(Collections2.transform(list2, TO_UPPER));

, который восстановит эффективный поиск, возвращая фильтрацию в O(n) вместо O(n^2).

.
1
ответ дан 2 December 2019 в 19:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: