为什么Sort(s1)== Sort(s2)比Counter(s1)更好使用== Counter(s2)

时间:2016-11-26 00:12:26

标签: python string

这被认为是检查两个字符串是否相互排列的有效方法吗?使用两个字典会有什么区别? Counter是否针对python进行了更优化?

我想我应该澄清,我发布此帖的原因是这条评论:Check if two unordered lists are equal提到通过使用sort(s1)== sort(s2)检查两个字符串是否相同更有效。由于这是o(nlog(n)),你会认为Counter会有更好的运行时间。

2 个答案:

答案 0 :(得分:2)

在您引用的另一个问题中,J.F. Sebastian理论认为在几乎所有情况下使用sort比使用Counter更快,但他明智地指出,如果您真的在意,您应该衡量:“在实践中,它可能总是比collections.Counter()更快(尽管渐近O(n)时间比O(n*log(n))更好.sort()。如果重要的话,请测量它。”< / p>

这种测量如下所示。高点:

  • 最多大约10^6的列表大小,sort更快。

  • 随着列表大小的增加,这种优势逐渐减少。

  • 这些实验使用具有许多离散值的列表。如果列表具有适度高的重复值百分比,则基准可能会有所不同。

  • 这些测量表明,创建Counter的开销通常大于仅对数据进行排序的成本。考虑这一点的一种方法是查看Counter创建相对于log(n)方法的sort部分的开销。直到n变得相当大,Counter数据结构的算法优势才能开始得到足够的回报来证明这种开销。

  • 但请记住:对于较小的数据大小,速度优势可能无关紧要 - 除非您以高音量重复操作。从这个角度来看,对于大多数用例而言,从代码设计的角度来看,“算法正确”的方法(使用Counter)可能仍然会更好 - 因为如果数据很大,它会更快,如果数据很快就会更快数据很小。

代码:

import timeit, sys, random
from collections import Counter

def prep():
    random.shuffle(xs)
    random.shuffle(ys)

def use_counter():
    prep()
    return Counter(xs) == Counter(ys)

def use_sort():
    prep()
    xs.sort()
    ys.sort()
    return xs == ys

experiments = [
    (3, 10, 100000),
    (3, 100, 10000),
    (3, 1000, 1000),
    (3, 10000, 100),
    (3, 100000, 10),
    (3, 1000000, 1),
    (1, 10000000, 1),
]

for e in experiments:
    repeat, list_size, timeit_n = e
    xs = list(range(list_size))
    ys = list(range(list_size))
    r1 = timeit.repeat(use_counter, repeat = repeat, number = timeit_n)
    r2 = timeit.repeat(use_sort,    repeat = repeat, number = timeit_n)
    print
    print e
    print 'total  ', sum(r1), sum(r2)
    print 'm1/m2  ', min(r1) / min(r2)

示例输出(比率&gt; 1表示Counter较慢):

(3, 10, 100000)
total   5.06751918793 2.15432405472
m1/m2   2.34850470872

(3, 100, 10000)
total   3.16299915314 2.06651735306
m1/m2   1.52879303981

(3, 1000, 1000)
total   3.017786026 2.42989587784
m1/m2   1.24086325316

(3, 10000, 100)
total   3.06426525116 2.74061489105
m1/m2   1.11802891855

(3, 100000, 10)
total   3.66198205948 3.35467290878
m1/m2   1.1028159291

(3, 1000000, 1)
total   5.19361901283 5.08777713776
m1/m2   1.03125948765

(1, 10000000, 1)
total   20.0118789673 24.6061840057
m1/m2   0.813286569044

答案 1 :(得分:1)

它是O(n),所以在理论上是有效的。 function print_doc_count(i){ var str= "collection" + i.toString(); db.collection(str).count(function(err, res){ if(!err){ console.log("docs in collection: "+str+" = "+res); } }); } for(var i=1; i<=10; i++){ print_doc_count(i); } 一个字典子类,所以唯一的区别是你必须用Python构建字典,而不是让Counter类(声称是“高 - 性能“所以我假设在C中实现”这样做。两者都是相同的大O,但Counter会更快。

这是一个不同的大O,但对于短字符串,对两个字符串进行排序实际上比Counter快四倍。