按嵌套元组值排序列表

时间:2011-05-28 16:13:24

标签: python sorting tuples

是否有更好的方法通过嵌套元组值对列表进行排序,而不是编写提取嵌套元组值的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)]

我考虑过使用compose,但这不在标准库中:

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

我在libs中遗漏了哪些内容可以使这段代码变得更好?

实施应该合理地使用100k项目。

上下文:我想对直方图项目的字典进行排序。键是元组(a,b),值是计数。最后,项目应按计数递减,a和b排序。另一种方法是展平元组并直接使用itemgetter,但这样会产生很多元组。

4 个答案:

答案 0 :(得分:11)

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

答案 1 :(得分: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)元组的列表会自动按照你想要的方式排序(在元组上使用字典顺序)。

答案 2 :(得分: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))

答案 3 :(得分:0)

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

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%(在小型和大型数据集上都有),并且在我的Q6600(使用一个核心)上完成不到0.5秒就可以获得100k项目。因此,避免创建元组似乎没什么帮助。