首先对包含最长项目的列表进行排序

时间:2017-03-20 09:02:19

标签: python python-3.x sorting lambda

我正在使用lambda来修改sort的行为。

sorted(list, key=lambda item:(item.lower(),len(item)))

对包含元素A1,A2,A3,A,B1,B2,B3,B的列表进行排序,结果为A,A1,A2,A3,B,B1,B2,B3

我预期的排序列表为A1,A2,A3,A,B1,B2,B3,B

我已经尝试将len(item)包含在排序中,但这不起作用。如何修改lambda以便排序结果?

4 个答案:

答案 0 :(得分:6)

这是一种方法:

>>> import functools
>>> def cmp(s, t):
    'Alter lexicographic sort order to make longer keys go *before* any of their prefixes'
    ls, lt = len(s), len(t)
    if ls < lt:   s += t[ls:] + 'x'
    elif lt < ls: t += s[lt:] + 'x'
    if s < t: return -1
    if s > t: return 1
    return 0

>>> sorted(l, key=functools.cmp_to_key(cmp))
['A1', 'A2', 'A3', 'A', 'B1', 'B2', 'B3', 'B']

传统上,词典排序顺序其他相同的前缀后更长的字符串(即&#39; abc&#39;之前&#39; abcd&#39;)。

为了满足您的期望,我们首先要修复&#34;较短的字符串是通过添加较长字符串的剩余部分加上另一个字符使其成为两者中的较长者:

compare abc to defg     -->  compare abcgx to defg
compare a   to a2       -->  compare a2x to a2

functools.cmp_to_key()工具然后将比较功能转换为关键功能。

这可能看起来很多工作,但排序期望与内置的词典排序规则非常不一致。

FWIW,这是另一种写作方式,可能会或可能不会被认为更清晰:

def cmp(s, t):
    'Alter lexicographic sort order to make longer keys go *before* any of their prefixes'
    for p, q in zip(s, t):
        if p < q: return -1
        if q < p: return 1
    if len(s) > len(t): return -1
    elif len(t) > len(s): return 1
    return 0

逻辑是:

  • 逐个字符地比较,直到找到另一对
  • 不同的对以传统方式确定排序顺序
  • 如果没有不同的对,那么最长的输入就是第一个。
  • 如果没有不同的对且长度相等,则字符串相等。

答案 1 :(得分:1)

我的第一个答案是:只是否定len标准,只能根据该标准进行反转。

sorted(list, key=lambda item:(item.lower(),-len(item)))   # doesn't work!

但这不起作用,因为alpha排序和长度之间存在冲突。 Alpha排序首先放入小字符串。所以长度标准不起作用。

您需要合并两个条件。彼此之间没有明确的优先权。

我找到了一种方法:首先计算字符串的最大长度,然后将填充的chr(127)(最大字符,只要你使用ASCII)字符串作为键返回,这样最小的字符串就会被填充最后的大角色:他们总是排在最后。

l = ["A","B","A1","A2","A3","B1","B2","B3"]

maxlen = max(len(x) for x in l)
print(sorted(l, key=lambda item:item.lower()+chr(127)*(maxlen-len(item))))

结果:

['A1', 'A2', 'A3', 'A', 'B1', 'B2', 'B3', 'B']

由于显而易见的原因,BTW不会拨打您的列表list

答案 2 :(得分:0)

可以通过以下方式构建密钥:

  1. 每个项目的第一个字母
  2. 长度
  3. 项目本身
  4. 例如:

    >>> L = ['A1', 'B2', 'A', 'A2', 'B1', 'A3', 'B3', 'B']
    >>> print(sorted(L, key = lambda item: (item[0], -len(item), item)))
    ['A1', 'A2', 'A3', 'A', 'B1', 'B2', 'B3', 'B']
    

答案 3 :(得分:0)

我喜欢Tries,所以只是为了好玩,我写了一个基于Trie的解决方案:

class Trie():

    def __init__(self):
        self.data = {}

    def add(self, word):
        ref = self.data
        for char in word:
            ref[char] = char in ref and ref[char] or {}
            ref = ref[char]
        ref[''] = 1


def sorted_print(dct, prefix=''):
    sorted_keys = sorted(filter(bool, dct.keys()), key=str.lower)
    for key in sorted_keys:
        v = dct[key]
        if isinstance(v, dict):
            sorted_print(v, prefix + key)
    if '' in dct:
        print(prefix)

my_list = ["B1", "B3", "B2", "A1", "A2", "A3", "A", "B"]
t = Trie()
for w in my_list:
    t.add(w)


sorted_print(t.data)
# A1
# A2
# A3
# A
# B1
# B2
# B3
# B

这适用于任何长度的任何字符串。

请注意,结果只是打印到屏幕上,而不是写回新列表。你没有写太多代码,所以我会把它留作练习;)