【问题标题】:Produce all possible equivalent sorts for a given key function为给定的键函数生成所有可能的等效排序
【发布时间】:2017-10-06 01:25:35
【问题描述】:

说我有积分:

points = [(1., 1.), (3., 0.), (-1., -1.), (9., 2.), (-4., 2.) ]

如果我按 y 轴对它们进行排序:

 points = sorted(points , key=lambda k: [k[1], k[0]])

我明白了

 points = [(-1., -1.),  (3., 0.), (1.,1.) , (-4.,2.), (9., 2.)]

但是我想完全独立于 x 轴对其进行排序。 此外,我希望输出是显示两种可能排序的 2 个列表(即 y 值相等的 x 值的所有排列):

[(-1., -1.),  (3., 0.), (1.,1.) , (-4.,2.),(9., 2.)]
[(-1., -1.),  (3., 0.), (1.,1.) , (9.,2.), (-4.,2.)]

有什么办法可以做到吗?

【问题讨论】:

  • 请不要为变量使用内置函数的名称;例如,将list 替换为points;这将为您节省很多悲伤(以及其他人)!

标签: python sorting grouping permutation equivalence-classes


【解决方案1】:

问题陈述:

在给定等价关系的情况下创建所有可能排列的多个列表(例如比较 y 坐标并忽略 x 坐标):

解决方案:

这里有一些解决问题的工作代码:

from operator import itemgetter
from itertools import groupby, product, permutations, chain

points = [(1., 1.),  (3., 0.),(-1., -1.) , (9., 2.), (-4., 2.) ]
points.sort(key=itemgetter(1))
groups = [list(permutations(g)) for k, g in groupby(points, itemgetter(1))]
for t in product(*groups):
    print(list(chain.from_iterable(t)))

最终结果:

[(-1.0, -1.0), (3.0, 0.0), (1.0, 1.0), (9.0, 2.0), (-4.0, 2.0)]
[(-1.0, -1.0), (3.0, 0.0), (1.0, 1.0), (-4.0, 2.0), (9.0, 2.0)]

解释:

  • 初始排序仅按 y 轴对点进行排序。这使用itemgetter() 提取字段1。

  • groupby() 步骤创建具有相同 y 坐标的点组。

  • permutations() 步骤生成每个组的所有可能排序。

  • product() 步骤生成每个排列组的笛卡尔积(因此每个输出都有来自每个排列组的一个元素)。

  • chain.from_iterable() 步骤将产品中的连续元组链接到单个可迭代对象中,可以将其馈送到 list() 以获得所需的结果。

一步一步:

1) 按 y 坐标对点进行排序,忽略 x 坐标:

>>> points = [(1., 1.),  (3., 0.),(-1., -1.) , (9., 2.), (-4., 2.)]
>>> points.sort(key=itemgetter(1))
>>> points
[(-1.0, -1.0), (3.0, 0.0), (1.0, 1.0), (9.0, 2.0), (-4.0, 2.0)]
>>>       ^-----------^-----------^-----------^-------------^ ascending y-values

2) 创建具有相同 y 坐标的点组:

>>> pprint([list(g) for k, g in groupby(points, itemgetter(1))], width=40)
[[(-1.0, -1.0)],                                            # y = -1.0  
 [(3.0, 0.0)],                                              # y =  0.0
 [(1.0, 1.0)],                                              # y =  1.0 
 [(9.0, 2.0), (-4.0, 2.0)]]                                 # y =  2.0 

3) 生成具有相同 y 坐标的点的所有排列:

>>> groups = [list(permutations(g)) for k, g in groupby(points, itemgetter(1))]
>>> pprint(groups)
[[((-1.0, -1.0),)],                                         # y = -1.0
 [((3.0, 0.0),)],                                           # y =  0.0 
 [((1.0, 1.0),)],                                           # y =  1.0 
 [((9.0, 2.0), (-4.0, 2.0)), ((-4.0, 2.0), (9.0, 2.0))]]    # y =  2.0

4) 使用每个排列组中的一个元素创建所有可能的序列:

>>> for t in product(*groups):
        print(t)

(((-1.0, -1.0),), ((3.0, 0.0),), ((1.0, 1.0),), ((9.0, 2.0), (-4.0, 2.0)))
(((-1.0, -1.0),), ((3.0, 0.0),), ((1.0, 1.0),), ((-4.0, 2.0), (9.0, 2.0)))

5) 将每个子序列组合成一个列表:

>>> for t in product(*groups):
        list(chain.from_iterable(t))

[(-1.0, -1.0), (3.0, 0.0), (1.0, 1.0), (9.0, 2.0), (-4.0, 2.0)]
[(-1.0, -1.0), (3.0, 0.0), (1.0, 1.0), (-4.0, 2.0), (9.0, 2.0)]

【讨论】:

    【解决方案2】:

    仅对 x 值进行排序:

        points = sorted(points , key=lambda k: k[1])
        points
    
        [(-1.0, -1.0), (3.0, 0.0), (1.0, 1.0), (9.0, 2.0), (-4.0, 2.0)]
    

    【讨论】:

    • 所以这会给我你刚刚证明和排序的列表(list , key=lambda k: [k[1], k[0]]) 会给我我提到的那个但想象一下还有 (2,2) 这些解决方案也行不通
    • 目前还不完全清楚您想要的第二个订单是什么;你能澄清一下吗?
    • 我想要的是给我关于 x 值的 y 的所有可能排序顺序的东西,所以如果只有 2 个数字重复,你写的和我所拥有的将解决这个问题但是问题不会如果我们有一个 y 轴为 2 的第三个数字,则可以解决
    猜你喜欢
    • 2012-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-16
    • 2011-05-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多