2011-05-28 86 views
5

有没有更好的方式来排序嵌套元组值的列表比写一个itemgetter替代提取嵌套元组值:排序列表值

def deep_get(*idx): 
    def g(t): 
     for i in idx: t = t[i] 
     return t 
    return g 

>>> l = [((2,1), 1),((1,3), 1),((3,6), 1),((4,5), 2)] 
>>> sorted(l, key=deep_get(0,0)) 
[((1, 3), 1), ((2, 1), 1), ((3, 6), 1), ((4, 5), 2)] 
>>> sorted(l, key=deep_get(0,1)) 
[((2, 1), 1), ((1, 3), 1), ((4, 5), 2), ((3, 6), 1)] 

我想过使用撰写,但是这不在标准库中:

sorted(l, key=compose(itemgetter(1), itemgetter(0)) 

有没有什么我错过了在库中,这将使这段代码更好?

该实施应该与100k项目合理合作。

上下文:我想排序一个直方图项目的字典。键是一个元组(a,b),值是计数。最后,这些项目应按降序a和b排序。另一种方法是平滑元组并直接使用itemgetter,但这样会产生大量的元组。

+0

有没有我知道的。你的方法很好,因为它是恕我直言。 – 2011-05-28 16:25:00

+0

“实施应该合理地处理10万件物品。” - 这条线是不必要的;所有使用'sort'的实现都可以在100k条件下合理运行 – ninjagecko 2011-05-28 18:18:33

+0

@ninjagecko如果对3个条目或100k或1T进行排序,实现将会有所不同。 – 2011-05-30 06:55:58

回答

8

是的,你可以只使用一个key=lambda x: x[0][1]

+0

'itemgetter(0)'比'lambda x:x [0]'更快吗? 'compose(itemgetter(1),itemgetter(0))','lambda x:x [0] [1]'和'deep_get'具有相同的性能特征吗? – 2011-05-28 16:23:44

+0

lambda几乎肯定会比所有这些都快,但由于排序,它仍然是'O(N log(N))',所以我不会担心太多;有可能更好的东西来优化 – ninjagecko 2011-05-28 16:34:49

+1

我认为itemgetter会比lambda更快,因为它是用C编写的。你为什么认为lambda更快? – utdemir 2011-05-28 16:46:05

2

你的做法是相当不错的,因为你的数据结构。

另一种方法是使用另一种结构。

如果你想要速度,去因子标准NumPy是要走的路。它的工作是有效处理大型数组。它甚至为你的数组提供了一些很好的排序例程。这里是你如何会在写你的排序上的计数,然后(A,B):

>>> arr = numpy.array([((2,1), 1),((1,3), 1),((3,6), 1),((4,5), 2)], 
        dtype=[('pos', [('a', int), ('b', int)]), ('count', int)]) 
>>> print numpy.sort(arr, order=['count', 'pos']) 
[((1, 3), 1) ((2, 1), 1) ((3, 6), 1) ((4, 5), 2)] 

这是非常快的(它是用C实现的)。

如果你想坚持使用标准的Python,包含(count,a,b)元组的列表会自动按照你想要的方式被Python排序(它使用元组的字典顺序)。

0

我比较了两种类似的解决方案。第一个使用一个简单的λ:

def sort_one(d): 
    result = d.items() 
    result.sort(key=lambda x: (-x[1], x[0])) 
    return result 

注上x[1]负,因为你想的那种要在数下降。

第二个利用了Python中的sort稳定的事实。首先,我们按(a, b)排序(升序)。然后我们排序算,下降:

def sort_two(d): 
    result = d.items() 
    result.sort() 
    result.sort(key=itemgetter(1), reverse=True) 
    return result 

第一个是快10-20%(包括小型和大型数据集),和0.5秒下既要完成我的Q6600(使用一个核心)为10万项。所以避免创建元组似乎没有多大帮助。

1

这可能是你的做法有点更快的版本:

l = [((2,1), 1), ((1,3), 1), ((3,6), 1), ((4,5), 2)] 

def deep_get(*idx): 
    def g(t): 
     return reduce(lambda t, i: t[i], idx, t) 
    return g 

>>> sorted(l, key=deep_get(0,1)) 
[((2, 1), 1), ((1, 3), 1), ((4, 5), 2), ((3, 6), 1)] 

这可能是缩短为:

def deep_get(*idx): 
    return lambda t: reduce(lambda t, i: t[i], idx, t) 

甚至只是简单地写出:

sorted(l, key=lambda t: reduce(lambda t, i: t[i], (0,1), t))