我知道这是一个愚蠢的问题,但我觉得有人可能想知道(或通知< redacted>同事)。我没有附加特定的编程语言,因为我认为它可以适用于所有这些语言。如果我错了,请纠正我。
主要问题:在常量String
或List<String>
中查找条目是否更快和/或更好?
详细信息:让我们说我想查看给定扩展名是否在受支持的扩展名列表中。以下哪项是最好的(关于编程风格)和/或最快:
const String SUPPORTED = ".exe.bin.sh.png.bmp" /*etc*/;
public static bool IsSupported(String ext){
ext = Normalize(ext);//put the extension in some expected state like lowercase
//String.Contains
return SUPPORTED.Contains(ext);
}
final static List<String> SUPPORTED = MakeAnImmutableList(".exe", ".bin", ".sh",
".png",".bmp" /*etc*/);
public static bool IsSupported(String ext){
ext = Normalize(ext);//put the extension in some expected state like lowercase
//List.Contains
return SUPPORTED.Contains(ext);
}
答案 0 :(得分:2)
首先,重要的是要注意解决方案在功能上并不相同。对于x
和exe.bin
等字符串,子字符串搜索将返回 true ,而List<String>.contains()
则不会。从这个意义上讲,List<String>
版本可能更接近您想要的语义。任何可能的性能比较都应牢记这一点。
现在,关于表现。
从渐近和算法复杂性的角度来看,随着字符串长度的增长,List<String>.contains()
方法将比另一种方法更快。从概念上讲,String.contains
版本需要在SUPPORTED
字符串中的每个位置中查找匹配,而List.contains()
版本只需要在开始时匹配每个子字符串 - 一旦在当前候选中找到不匹配,它就会跳到下一个。这与上述注释相关,即选项在功能上并不等同:String.contains
选项在理论上可以匹配更广泛的输入,因此在拒绝候选之前必须做更多的工作。
复杂性方面,如果您将N视为候选人数<{1}},O(N)
与List.contains()
O(N^2)
之间的区别可能类似String.contains()
/ em>并假设每个候选人都有一个有限的长度,并且通常的暴力中的String.contains()
方法“寻找从每个位置开始的匹配”算法。事实证明,Java String.contains()
实现并不完全是基本的O(N^2)
搜索,但它也没有做Boyer-Moore。一般来说,一旦子串足够长,List.String
方法就会更快。
从更接近金属的角度来看,这两种方法都有其优势。 String.contains()
解决方案避免了迭代List
元素的开销:整个调用将用于内部化String.contains
实现,而所有char
构成整个调用SUPPORTED
字符串是连续的,所以这是对内存友好的。 List.contains()
方法会花费大量时间进行双重解除引用,从每个List
元素到包含的String
再到包含的char[]
数组,如果您所比较的字符串很短,这可能会占主导地位。
另一方面,List.contains
解决方案最终调用String.equals
,这可能是以Arrays.equal(char[], char[])
实现的,它在x86平台上使用SSE和AVX内在函数进行了大量优化,可能是即使与String.contains()
的优化版本相比,速度也很快。因此,如果字符串变长,再次期望List.contains()
继续前进。
所有这一切,有一种简单,规范的方法可以快速完成:HashSet<String>
包含所有候选字符串。这只是一个简单的String.hash()
(缓存,通常是“免费”)和哈希表中的单个查找。
答案 1 :(得分:1)
嗯,它可能因实现而异,但如果想以一般化的方式来看待这个问题,请看看。
如果你想在字符串中查找特定的子字符串,假设在包含不同扩展名的不可变字符串中的文件扩展名,你只需要遍历带有扩展名的字符串一次。
另一方面,使用不可变字符串列表,仍然需要遍历该列表中的每个字符串加上迭代该列表的开销。
作为结论,以一种通用的方式,您可以看到使用列表来存储字符串需要更多的处理。
但是,您可以通过其可读性,可维护性等来查看这两种解决方案。例如,如果要添加或删除新扩展或应用更复杂的操作,可能需要使用字符串列表来节省开销。