簡體   English   中英

用數字和字母對列表進行排序

[英]Sort list with numbers and letters

我正在嘗試對包含數字和字母的列表進行排序:

names = ["5aG", "6bG", "10cG", "J1", ...]

輸出應如下所示:

['5aG', '5bG', '5aR', '5bR', '6aG', '6bG', '6cG', '6aR', '6bR', '7aG', '7bG', '7aR', '8aG', '8bG', '8aR', '9aG', '9bG', '9aR','10aG', '10bG', '10cG', '10aR', 'J1', 'J2']

字符串的第一個元素始終是 5 - 10 之間的數字,然后是 a - c 中的一個字母,最后還有另一個字母(“G”或“R”)。

此外還有字符串“J1”和“J2”。 它們應該總是最后一個(“J1”在“J2”之前)。

我怎樣才能實現這樣的目標? 我想過使用 lambda 函數。

到目前為止,我對其進行了硬編碼,但我認為應該有更好的解決方案。
這是我的硬編碼版本:

classes = ['5aG', '5bG', '5aR', '5bR', '6aG', '6bG', '6cG', '6aR', '6bR', '7aG', '7bG', '7aR', '8aG', '8bG', '8aR', '9aG', '9bG', '9aR','10aG', '10bG', '10cG', '10aR', 'J1', 'J2']

def s(v):
  """Get index of element in list"""
  try:
    return classes.index(v)
  except ValueError:
return 500

l = ['5bG', '6aG', '6bG', '8aR', '9aG', '9bG', '9aR', '10cG', '10aR', 'J1', 'J2', '5aG', '']
w = sorted( l, key=s)
print(w)

您可以使用re提取前面的整數,然后依靠tuple比較。

import re

def key(s):
    num, letters = re.match(r'(\d*)(.*)', s).groups()
    return float(num or 'inf'), letters

sorted_names = sorted(names, key=key)

請注意如何依靠float('inf')將沒有前綴數字的令牌推到最后。

你可以試試這個:

加擾所需的輸出后:

import re
s = ['5aR', '7aR', '10aR', '10cG', '9bG', '8aR', '8bG', '6bR', '5aG', '9aG', 'J1', '6aR', '6aG', '5bR', '7aG', '7bG', '9aR', '5bG', 'J2', '6bG', '10bG', '8aG', '10aG', '6cG']
c, d, *h = sorted(s, key=lambda x:[False if not x[0].isdigit() else int(re.findall('^\d+', x)[0]), x[-1], x[-2]])
sorted_result = [*h, c, d]

輸出:

['5aG', '5bG', '5aR', '5bR', '6aG', '6bG', '6cG', '6aR', '6bR', '7aG', '7bG', '7aR', '8aG', '8bG', '8aR', '9aG', '9bG', '9aR', '10aG', '10bG', '10cG', '10aR', 'J1', 'J2']

這是一種方法。

lst = ['7aR', '9aG', '7bG', '10cG', '5bG', '6aG', '6bG', '10bG', 'J2', '5aR', '10aG', '9bG', '6aR', '7aG', '10aR', '9aR', '8aR', 'J1', '5bR', '6bR', '5aG', '8bG', '6cG', '8aG']

sorted([i for i in lst if i[0]!='J'], key=lambda x: [int(x[:-2]), x[-1], x[-2]]) + \
sorted(i for i in lst if i[0]=='J')

# ['5aG', '5bG', '5aR', '5bR', '6aG', '6bG', '6cG', '6aR', '6bR', '7aG', '7bG', '7aR', '8aG', '8bG', '8aR', '9aG', '9bG', '9aR', '10aG', '10bG', '10cG', '10aR', 'J1', 'J2']

最簡單的方法是使用 Python 的內置排序函數。 通過提供合適的函數作為key參數,您可以按您選擇的任何順序對事物進行排序。

在內部,當您提供鍵函數時,排序會生成一個包含兩個元素的元組列表。 元組的第一個元素是排序鍵,是將鍵函數應用於第二個元素的結果,即列表中的值。 然后對這些元組進行排序,並返回第二個元素的列表。 這稱為裝飾-排序-取消裝飾。

大多數字符串都是一個整數,后跟兩個字母。 您希望最后出現的其余部分是"J1""J2" 以下應該是一個合適的按鍵功能。 我采取了將int函數應用於數字的預防措施,以確保它們按數字而不是按字典順序排序(因為'2' > '10' )。

def key_func(s):
    # Ensure J-strings are at the end
    if s.startswith('J'):
        return (1000000, 'J', int(s[1:]))
    else:
        # The rest, split into digits and two characters
        return (int(s[:-2]), s[-2], s[-1])

使用隨機數據副本進行測試時,結果為

data = ['8aG', '5aR', '6aG', '10aG', '6cG', '8bG', '9aG',
        '5aG', '6bG', '7aR', 'J1', '10cG', '10bG', '10aR',
        '6bR', 'J2', '6aR', '8aR', '7aG', '9aR', '5bR',
        '9bG', '7bG', '5bG']
print(sorted(data, key=key_func))

似乎是正確的(為了可讀性插入換行符):

['5aG', '5aR', '5bG', '5bR', '6aG', '6aR', '6bG', '6bR',
 '6cG', '7aG', '7aR', '7bG', '8aG', '8aR', '8bG', '9aG',
 '9aR', '9bG', '10aG', '10aR', '10bG', '10cG', 'J1', 'J2']

使用自定義compound_sort()函數:

import re

lst = ['9bG', '9aR', 'J2', '7bG', '7aG', '6bR', 'J1', '6cG', '6aG', '6bG', '5bG', '5aG', '8bG', '5bR', '8aR', '5aR', '10aR', '6aR', '10bG', '10aG', '9aG', '10cG', '7aR', '8aG']
pat = re.compile(r'(\d+)(.*)|(J)(\d+)')

def compound_sort(t):
  t = tuple(filter(None, t))    # filter empty(None) matches
  return (int(t[0]),) + t[1:] if t[0] != 'J' else (float('inf'), t[1])

result = sorted(lst, key=lambda x: compound_sort(pat.search(x).groups()))
print(result)

輸出:

['5aG', '5aR', '5bG', '5bR', '6aG', '6aR', '6bG', '6bR', '6cG', '7aG', '7aR', '7bG', '8aG', '8aR', '8bG', '9aG', '9aR', '9bG', '10aG', '10aR', '10bG', '10cG', 'J1', 'J2']

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM