我正在尝试按列对csv文件进行排序。该文件有许多列,如下所示:
汤姆,01AA01,234.56,334
翘,01AS01,546.09,3434.3
山姆,01NA01,4574.3,65.45
乐,01BA01,2897.03,455
帕姆,01MA01,434.034,454
约翰,01AA02,343,24
翘,01AS02,454,454.54
汤姆,02BA01,3434,3454.2
它继续大约20列和250行。
我希望它按第二列排序,并按字母顺序排列第二部分中的AA
,AS
,BA
,以及数字上第三部分'01',' 02','03',数字上为第一部分'01','02','03'。然后从这种类型创建一个新的csv文件。它们通常不只有6个字符,其他看起来像'02BAA','01MAA','02NAA'等等。
所以最终希望第2列看起来像这样。
01AA01
01AS01
01BA01
01MA01
01NA01
01AA02
01AS02
02BA01
我是编码的新手,并不太清楚如何去做。提前谢谢。
答案 0 :(得分:1)
来自Python的sorted
函数的ASCII字符串的默认排序顺序是lexicographic(或'ASCIIbetical'):
>>> li=['1', '20', '100', '11']
>>> sorted(li)
['1', '100', '11', '20']
与整数幅度相比,这些列表值是整数:
>>> sorted(map(int, li))
[1, 11, 20, 100]
即,人眼中弦的数量的大小与计算机眼中的相同弦的大小不同。 (更详尽地写在Codinghorror)
要修复它,我们需要将数字与数字分开,并将数字转换为整数(或浮点数)。
最简单的方法是使用正则表达式捕获所有数字,然后将所有数字转换为整数。
这将分类到您的目标中:
li1='''\
01AA01
01AS01
01NA01
01BA01
01MA01
01AA02
01AS02
02BA01'''.splitlines()
tgt='''\
01AA01
01AS01
01BA01
01MA01
01NA01
01AA02
01AS02
02BA01'''.splitlines()
import re
def kf(s):
nums=map(int, re.findall(r'(\d+)', s))
lets=re.findall(r'([a-zA-Z]+)', s)
return nums+lets
print tgt==sorted(li1, key=kf)
# True
或者,一行:
>>> tgt==sorted(li1, key=lambda s: map(int, re.findall(r'(\d+)', s))+re.findall(r'(\D+)', s))
True
根据评论进行修改
问题的文字表明:
我希望在第一部分01,02,03中以数字方式订购... 然后按字母顺序排列第二部分的AA,AS,BA,和 数字再次为第三部分。
但是,示例表明情况并非如此。
我们可以使用split:
对(int,letters,int)的模式进行排序>>> [re.split(r'(\D+)', e) for e in li1]
[['01', 'AA', '01'], ['01', 'AS', '01'], ['01', 'NA', '01'], ['01', 'BA', '01'], ['01', 'MA', '01'], ['01', 'AA', '02'], ['01', 'AS', '02'], ['02', 'BA', '01']]
>>> sorted(li1, key=lambda s: [int(e) if e.isdigit() else e for e in re.split(r'(\D+)', s)])
['01AA01', '01AA02', '01AS01', '01AS02', '01BA01', '01MA01', '01NA01', '02BA01']
# ^^ ^^ etc '01AA02', before '01AS01' in the example
通过检查,POSTED示例的模式为(int, int, letters)
,可以在此处看到:
>>> [map(int, re.findall(r'(\d+)', s))+re.findall(r'(\D+)', s) for s in li1]
[[1, 1, 'AA'], [1, 1, 'AS'], [1, 1, 'NA'], [1, 1, 'BA'], [1, 1, 'MA'], [1, 2, 'AA'], [1, 2, 'AS'], [2, 1, 'BA']]
如果 TEXT 是正确的,请使用我所拥有的拆分形式;如果 EXAMPLE 正确,请使用nums+lets
表单。
答案 1 :(得分:0)
sorted()
和列表的.sort()
方法采用可选的key
参数。
<强>其中:强>
key 指定一个参数的函数,用于提取 每个列表元素的比较键:key = str.lower。
换句话说,给予key参数的函数(你将要编写)解析并返回给定对象的 sortable 值。
因此,根据您的输入"01AS01"
,您希望将其分解为可以轻松排序的部分。
正如您所提到的,您希望按( int,str,int )排序结果。由于sorted()
和.sort()
会自动按数字排序,(如果是),按字母顺序排列,(如果是字符串),您只需要为您的关键功能做的就是打破您的价值,"01AS01"
进入[1, "AS", 1]
,而sorted()
/ .sort()
会处理其余的事情。
这是与dawg相似的示例,但未使用map()
和re
。
col = ['01AA01',
'01AS01',
'01NA01',
'01BA01',
'01MA01',
'01AA02',
'01AS02',
'02BA01']
def create_sort_key(value):
int_indexes = (0, 4)
str_indexes = (2,)
parsed_values = []
# get the starting index for groups of two
for i in range(0, 6, 2):
pair = value[i:i+2]
if i in int_indexes:
parsed_value = int(pair)
elif i in str_indexes:
parsed_value = str(pair)
else:
raise IndexError("unexpected index: {}".format(i))
parsed_values.append(parsed_value)
return parsed_values
col.sort(key=create_sort_key)
答案 2 :(得分:0)
假设这是一个csv文件,每行都是一行,每列都用逗号标记。既然没有给我们一个你的csv的例子,我组成了一个有两列,你的数据在col [1]。
>>> print open('mycsv.csv').read()
fred, 01AA01
brenda, 01BA01
bob, 01AA02
alice, 01NA01
jane, 01AS01
blane, 02BA01
larry, 01MA01
mary, 01AS02
这些都可以通过csv模块读入列表。最终得到一个行列表,其中列是另一个列表
>>> import csv
>>> table=[row for row in csv.reader(open('mycsv.csv')) if row]
>>> print table
[['fred', ' 01AA01'], ['brenda', ' 01BA01'], ['bob', ' 01AA02'], ['alice', ' 01NA01'], ['jane', ' 01AS01'], ['blane', ' 02BA01'], ['larry', ' 01MA01'], ['mary', ' 01AS02']]
您可以对该列表进行排序。默认情况下,排序从第一个键开始,然后是第二个键,如果第一个键是相同的,等等。因此,它将由#fred&#39;等...但您可以选择不同的排序键。 Python使用每个列表项调用键函数,以便您可以将其转换为您想要的。转换可以很简单,比如小写或复杂。
将lambda用于排序键是常见的,但这可能有点高级,所以这里只是抓住你想要的键的功能。
>>> def item_1(row):
... return row[1]
...
>>> print table
[['fred', ' 01AA01'], ['bob', ' 01AA02'], ['jane', ' 01AS01'], ['mary', ' 01AS02'], ['brenda', ' 01BA01'], ['larry', ' 01MA01'], ['alice', ' 01NA01'], ['blane', ' 02BA01']]
>>>