【问题标题】:Is there a clean way to ignore case when comparing List<String>?比较 List<String> 时是否有一种干净的方法来忽略大小写?
【发布时间】:2016-03-31 20:02:36
【问题描述】:

现在我有类似的东西:

boolean areListsDifferent = (list1.size() == list2.size()) ? false : true;
for(String string : list1){
    if(!list2.contains(string.toLowerCase())){
        // This sucks because it assumes list2 is all lower case, 
        // which is probably true but presumptuous
        areListsDifferent = true;
    }
}
return areListsDifferent;

这似乎有点冗长,而且我真的不想假设第二个列表都是小写的。这使得它对未来的变化更加脆弱。

有没有更好的方法?

【问题讨论】:

  • equalsIgnoreCase() 似乎是您正在寻找的东西。
  • List 是一个有序元素的集合。两个列表通常只有在排序匹配时才相同,并且您的代码会忽略顺序。这是你的意图吗?
  • 您假设没有重复项。例如 A, b, b, b 将匹配 a, a, b, ba, B, B, B
  • 由于您在检查列表的大小后没有返回,因此即使您已经确定它们不同,您也将遍历这两个列表。在尺寸检查后贴上退货声明。
  • 顺序无关紧要。重复也不重要。对于这种情况,当列表功能相同时返回 true 只是意味着幂等操作被浪费地运行,所以这没什么大不了的。唯一重要的是,如果列表不同,则永远不要返回 true。

标签: java string list


【解决方案1】:

由于您在比较大小,我假设顺序是相关的,因为列表是有序集合。问题中显示的代码忽略了顺序。

要不区分大小写地比较所有元素,您应该按顺序并行迭代两个列表。由于get(int) 并不是所有List 实现都很快,因此最好使用Iterator 进行并行迭代:

private static boolean equalsIgnoreCase(List<String> list1, List<String> list2) {
    if (list1.size() != list2.size())
        return false;
    for (Iterator<String> iter1 = list1.iterator(), iter2 = list2.iterator(); iter1.hasNext(); )
        if (! iter1.next().equalsIgnoreCase(iter2.next()))
            return false;
    return true;
}

【讨论】:

    【解决方案2】:

    我假设您想要比较 2 个列表。

    确保两个列表都不为空。

    if(list1 == null || list2 == null) return false;
    

    检查尺寸。

    if(list1.size() != list2.size()) return false;
    

    检查列表中的元素(包括字符串的顺序(?),但不包括大小写)

    for(int i = 0 ; i < list1.size() ; i++) {
        // i think equalsIgnoreCase takes care of null strings
        // if it doesn't, do it yourself :)
        String first = list1.get(i);
        String second = list2.get(i);
        if(first == null && second != null)
            return false;
        if(first == null && second == null)
            continue;
        if( !(first.equalsIgnoreCase(second)) )
            return false;
    }
    

    如果你来了。一切可能都很好。

    return true;
    

    正如 Andreas 所指出的,对于像 LinkedList 这样实现的列表,get(..) 的性能很差。一个基于iterator 的方法就像他的回答一样解决了这个问题。

    【讨论】:

    • 如果列表是 LinkedList 或其他非数组实现,则使用 get() 会导致性能不佳。 --- equalsIgnoreCase 不处理左侧的 null。
    【解决方案3】:

    根据您的说明:

    顺序无关紧要。重复也不重要。

    然后我会首先将数据放入具有这些属性的某种SortedSet 中。比如:

    var set1 = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
    var set2 = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
    set1.addAll(list1);
    set2.addAll(list2);
    return set1.equals(set2);
    

    这应该比在一个列表上循环并在另一个列表上重复调用contains (O(N^2)) 运行得更快 (O(N log N)) - 一旦您的列表包含超过 ~10 个元素,就会很明显。

    【讨论】:

      猜你喜欢
      • 2010-11-26
      • 2010-09-17
      • 1970-01-01
      • 2010-11-07
      • 2021-02-15
      • 2016-01-29
      • 1970-01-01
      相关资源
      最近更新 更多