集合removeAll忽略大小写?
好的,这是我的问题。 我必须使用 HashSet
,我使用 removeAll
方法从一组中删除存在于另一组中的值。
在调用该方法之前,我显然将值添加到 Set
中。 在添加之前,我对每个 String
调用 .toUpperCase()
,因为两个列表中的值大小写不同。 这个案子没有任何规律或理由。
调用 removeAll
后,我需要取回 Set
中剩余值的原始情况。 有没有一种有效的方法可以做到这一点,而无需运行原始列表并使用CompareToIgnoreCase?
示例:
List1:
"BOB"
"Joe"
"john"
"MARK"
"dave"
"Bill"
List2:
"JOE"
"MARK"
"DAVE"
此后,在 String
上使用 toUpperCase()
为每个 List 创建一个单独的 HashSet
。 然后调用removeAll
。
Set1.removeAll(set2);
Set1:
"BOB"
"JOHN"
"BILL"
我需要让列表再次看起来像这样:
"BOB"
"john"
"Bill"
任何想法将不胜感激。 我知道它很差,原始列表应该有一个标准,但这不是我可以决定的。
Ok so here is my issue. I have to HashSet
's, I use the removeAll
method to delete values that exist in one set from the other.
Prior to calling the method, I obviously add the values to the Set
s. I call .toUpperCase()
on each String
before adding because the values are of different cases in both lists. There is no rhyme or reason to the case.
Once I call removeAll
, I need to have the original cases back for the values that are left in the Set
. Is there an efficient way of doing this without running through the original list and using CompareToIgnoreCase
?
Example:
List1:
"BOB"
"Joe"
"john"
"MARK"
"dave"
"Bill"
List2:
"JOE"
"MARK"
"DAVE"
After this, create a separate HashSet
for each List using toUpperCase()
on String
s. Then call removeAll
.
Set1.removeAll(set2);
Set1:
"BOB"
"JOHN"
"BILL"
I need to get the list to look like this again:
"BOB"
"john"
"Bill"
Any ideas would be much appreciated. I know it is poor, there should be a standard for the original list but that is not for me to decide.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
在我原来的答案中,我不假思索地建议使用
Comparator
,但这会导致TreeSet
违反equals
contract 并且是一个正在等待的错误发生的情况:最好使用专用类型:
此代码不太可能导致错误:
不幸的是,这更冗长。
In my original answer, I unthinkingly suggested using a
Comparator
, but this causes theTreeSet
to violate theequals
contract and is a bug waiting to happen:It is better to use a dedicated type:
This code is less likely to cause bugs:
This is, unfortunately, more verbose.
可以通过以下方式完成:
TreeSet
中,String
,感谢TreeSet#removeAll( Collection c)
ArrayList#retainAll(Collection c)
将迭代列表的元素,并且对于每个元素在提供的集合上调用contains(Object o)
来了解是否应该保留该值,这里由于集合不区分大小写,我们将只保留String
与我们提供的 TreeSet 实例中的内容不区分大小写地匹配。相应的代码:
输出:
NB 1: 将第二个列表的内容放入
TreeSet
中非常重要,特别是如果我们不这样做的话知道它的大小,因为如果当前集合的大小严格大于当前集合的大小,则TreeSet#removeAll(Collection c)
的行为取决于两个集合的大小提供的集合,那么它将直接调用当前集合上的remove(Object o)
来删除每个元素,在这种情况下提供的集合可以是一个列表。 但如果相反,它将在提供的集合上调用contains(Object o)
来知道是否应该删除给定的元素,因此如果它不是不区分大小写的集合,我们就赢了得不到预期的结果。注意事项 2:上述方法
ArrayList#retainAll(Collection c)
的行为与方法默认实现的行为相同我们可以在
,这样该方法实际上适用于任何实现了AbstractCollection
中找到 >retainAll(Collection c)retainAll(Collection> 的集合。 c)
具有相同的行为。It could be done by:
TreeSet
s,String
s case-insensitively thanksTreeSet#removeAll(Collection<?> c)
ArrayList#retainAll(Collection<?> c)
will iterate over the elements of the list and for each element it will callcontains(Object o)
on the provided collection to know whether the value should be kept or not and here as the collection is case-insensitive, we will keep only theString
s that match case-insensitively with what we have in the providedTreeSet
instance.The corresponding code:
Output:
NB 1: It is important to have the content of the second list into a
TreeSet
especially if we don't know the size of it because the behavior ofTreeSet#removeAll(Collection<?> c)
depends on the size of both collections, if the size of the current collection is strictly bigger than the size of the provided collection, then it will call directlyremove(Object o)
on the current collection to remove each element, in this case the provided collection could be a list. But if it is the opposite, it will callcontains(Object o)
on the provided collection to know whether a given element should be removed or not so if it is not an case-insensitive collection, we won't get the expected result.NB 2: The behavior of the method
ArrayList#retainAll(Collection<?> c)
described above is the same as the behavior of the default implementation of the methodretainAll(Collection<?> c)
that we can find inAbstractCollection
such that this approach will actually work with any collections whose implementation ofretainAll(Collection<?> c)
has the same behavior.您可以使用 hashmap 和使用大写集作为映射到混合大小写集的键。
hashmap 的键是唯一的,您可以使用 HashMap.keyset() 获取一组键;
要检索原始大小写,就像 HashMap.get("UPPERCASENAME") 一样简单。
并根据 文档< /a>:
所以 HashMap.keyset().removeAll 将影响 hashmap :)
编辑:使用 McDowell 的解决方案。 我忽略了一个事实,即您实际上并不需要字母大写:P
You can use a hashmap and use the capital set as keys that map to the mixed case set.
Keys of hashmaps are unique and you can get a set of them using HashMap.keyset();
to retrieve the original case, it's as simple as HashMap.get("UPPERCASENAME").
And according to the documentation:
So HashMap.keyset().removeAll will effect the hashmap :)
EDIT: use McDowell's solution. I overlooked the fact that you didn't actually need the letters to be upper case :P
使用 google-collections 来解决这个问题将是一个有趣的问题。 您可以有一个像这样的常量谓词:
然后您所追求的可以像这样完成:
即:
请注意,
Collections2.transform
的输出不是一个高效的Set
实现,因此,如果您正在处理大量数据并且探测该列表的成本将会受到影响您可以改为使用它将恢复高效查找,将过滤返回到 O(n) 而不是 O(n^2)。
This would be an interesting one to solve using google-collections. You could have a constant Predicate like so:
and then what you're after could be done someting like this:
That is:
Note that the output of
Collections2.transform
isn't an efficientSet
implementation, so if you're dealing with a lot of data and the cost of probing that list will hurt you, you can instead usewhich will restore an efficient lookup, returning the filtering to O(n) instead of O(n^2).
据我所知,哈希集使用对象的 hashCode 方法来区分它们。
因此,您应该在对象中重写此方法,以便区分不同的情况。
如果您确实使用字符串,则无法重写此方法,因为您无法扩展 String 类。
因此,您需要创建自己的类,其中包含一个字符串作为属性,并用您的内容填充该属性。 您可能需要 getValue() 和 setValue(String) 方法来修改字符串。
然后你可以将你自己的类添加到哈希图中。
这应该可以解决你的问题。
问候
as far as i know, hashset's use the object's hashCode-method to distinct them from each other.
you should therefore override this method in your object in order to distinct cases.
if you're really using string, you cannot override this method as you cannot extend the String-class.
therefore you need to create your own class containing a string as attribute which you fill with your content. you might want to have a getValue() and setValue(String) method in order to modify the string.
then you can add your own class to the hashmap.
this should solve your problem.
regards