【问题标题】:How can I group tuples inside a list that have a similar value of one item and then sort them based on another item?如何在列表中对具有相似值的一个项目的元组进行分组,然后根据另一个项目对它们进行排序?
【发布时间】:2021-08-21 06:35:32
【问题描述】:

首先让我进一步解释一下我在问题中所说的内容。

我有一个包含矩形坐标的列表和这样的字符串:

list = [
       (x0, y0, x1, y1, 'string 1'),
       (x0, y0, x1, y1, 'string 2'),
       (x0, y0, x1, y1, 'string 3')
       ]

我的目标是通过升序 y1 和升序 x0 对它们进行排序

现在我正在使用这种方法对它们进行排序:

from operator import itemgetter
list.sort(key=itemgetter(3, 0))

问题是有时 y1 坐标彼此相似,它们会弄乱字符串的读取顺序。

这是一个简单的例子:

有序列表:

[
(859.0005493164062, 155.95175170898438, 942.1799926757812, 267.6641845703125, 'apple'), 
(797.2904663085938, 157.01016235351562, 824.2350463867188, 268.2728271484375, 'red'), 
(717.056640625, 157.71969604492188, 754.2953491210938, 269.064697265625, 'The'),
(162.12901306152344, 345.8944091796875, 210.24722290039062, 381.1226806640625, 'is'), 
(234.13601684570312, 346.3544006347656, 291.0986633300781, 381.9940185546875, 'trully'),
(313.343017578125, 347.2441101074219, 332.92852783203125, 382.7861328125, 'delicious'
]

如果我加入字符串,该短语将显示为“apple red The is trully delicious”,但它的意思是阅读“The red apple is trully delicious”。

我不能简单地颠倒顺序,或者先按 'x0' 排序,因为它会干扰列表中的其他元组并且更加混乱句子。

所以我想我正在寻找一个基于“y1”是否相似对元组进行分组的函数(我正在考虑做一个 if 'y'/'y' ~= 1 then group 但我知道如何处理两个以上的元组),然后按“x0”应用排序,最后将它们附加到一个新列表中。

感谢任何帮助!

编辑 1:尝试实现此功能:

import math
def round_down(n):
    multiplier = 10
    return math.floor(n/multiplier)*multiplier

这设法将坐标四舍五入到最低的十位,但也有坐标混乱。

我已经确定了我认为的问题。

这里有一些视觉帮助: 红色矩形是每个单词的边界框。绿线代表“y”坐标,在页面中下降时上升 10。蓝点是(x0, y0),紫点是(x1, y1)

问题在于蓝色和紫色的点最终位于绿线的不同侧。因为现在如果我将 'delicious' 的 'y1' 舍入到 180,如果我将 'y0' 舍入到 170。

所以现在我知道该诚实地做什么了。

也许创建一个更大的矩形,其中包含两个 'y1' 值之间的单词,对它们进行排序,然后移至下一组?

按照我最初的意图按类似的“y1”值分组也可以,因为我没有四舍五入任何值。

我真的不知道这些选项中的任何一个会如何工作,因为我在编程方面没有那么丰富的经验。因此,再次欢迎任何帮助!

【问题讨论】:

    标签: python


    【解决方案1】:

    如果你将它四舍五入到最接近的“10”,你会得到你想要的结果:

    >>> [x[-1] for x in sorted(l, key = lambda x: (round(x[3], -1), round(x[0], -1)))]
    ['The', 'red', 'apple', 'is', 'trully', 'delicious']
    
    编辑:

    要始终向下舍入,请使用math.floor

    import math
    >>> [x[-1] for x in sorted(l, key = lambda x: (math.floor(x[3]/10), math.floor(x[0]/10)))]
    ['The', 'red', 'apple', 'is', 'trully', 'delicious']
    

    【讨论】:

    • 感谢您的回复!这几乎可以做到。有些单词仍然混乱,因为同一行中的某些坐标以分隔单词的数字结尾。例如,165 舍入到 170 对吗?和 164 舍入到 160。所以现在它将这两个分开排序。有没有办法将它们都四舍五入到 160?
    • 我之前没有看到这个,但我已经更新了关于这个功能的帖子。
    • 我能够使用@alain-t 的方法解决它。谢谢你的帮助!
    【解决方案2】:

    您可能会在排序中使用自定义比较来获得所需的结果,当它们的差值低于给定阈值时,这些值被认为是相等的。

    Python 在排序函数中不再有比较选项并使用键生成函数,但您可以使用一个特殊的类来解决这个问题,该类将实现近似比较:

    data = [
    (859.0005493164062, 155.95175170898438, 942.1799926757812, 267.6641845703125, 'apple'), 
    (797.2904663085938, 157.01016235351562, 824.2350463867188, 268.2728271484375, 'red'), 
    (717.056640625, 157.71969604492188, 754.2953491210938, 269.064697265625, 'The'),
    (162.12901306152344, 345.8944091796875, 210.24722290039062, 381.1226806640625, 'is'), 
    (234.13601684570312, 346.3544006347656, 291.0986633300781, 381.9940185546875, 'trully'),
    (313.343017578125, 347.2441101074219, 332.92852783203125, 382.7861328125, 'delicious')
    ]
    
    class Approx:
        def __init__(self,value):
            self.value = value
        def __eq__(self,other):
            return abs(self.value-other.value)<2  # custom comparison
        def __lt__(self,other):
            if self == other: return False
            else: return self.value < other.value
            
    sd = sorted(data,key=lambda d:(Approx(d[3]),d[0]))
    
    print(*(d[-1] for d in sd))
    
    The red apple is trully delicious
    

    【讨论】:

    • 感谢您的回复!我有一个关于这个的问题。这条线 (return abs(self.value-other.value)&lt;2) 是什么决定了值的差异量以便将它们组合在一起?如果是这样,我可以更改“2”以使差异更大或更小吗?我问这个是因为有些词仍然混乱,我想这是因为差异不够大。
    • 我更改了“2”并解决了问题。非常感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-06
    • 2019-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-23
    相关资源
    最近更新 更多