对包含列表的列表进行排序

3
我有一个算法,会生成一个包含未知数量的子列表的列表,每个子列表中都有一个未知数量的字符串元素和一个浮点数。我需要按照这个浮点数对这些子列表进行排序,并保留子列表中字符串的顺序不变。
目前,我使用了下面链接中的一块代码来对其进行排序。但是我遇到了KeyError的问题。由于我以前没有接触过dict,所以我不确定该怎么做。如果有更好的方法,我也可以接受。链接如下:http://ideone.com/wr8UA 这些浮点数不是连续的。在运行时,数字偶尔会被跳过(在Ideone示例列表中它们是1.0、2.0、4.0;为了模拟这种情况)。它们也不在子列表中的任何特定位置,因此需要用多个for循环搜索它们。
希望我表述清楚了,我之前试图解释却只得到downvotes而不是关于什么让人困惑的问题。如果有什么不对的地方,请告诉我。谢谢大家!
编辑:请求在正文中放置代码。
listed = [ ["1 NWZ", "1 RWZ", "2 NWZ", "2 RWZ", "1E HZ", "1W HZ", "1-2EHZ", 2.0, "2W HZ"],
["1 NWZ", "1W HZ", "3E FZ", "SNOK", "POK", 3.0, "1-2EHZ", "2E AK", "2W HZ"],
["1 BW", "1AW AS", "3E FZ", "1BWAK", "POK", "TESTK", "1-2EHZ", "2E AK", 1.0]] 

dictionary={}
for sub_list in listed:
    for value in sub_list:
        if isinstance(value,float):
            dictionary[str(value)]=sub_list
        else:
            pass
ordered_list=[]
    for i in range(1,len(listed)+1):
    if dictionary[str(i)]:
        ordered_list.append(dictionary[str(i)])

for sub_list in ordered_list:
    print sub_list

1
请将问题中的代码放在里面,它并不是很长! - heltonbiker
1
@heltonbiker 当然可以,但我也会留下链接,因为它列出了错误和行号。 - zakparks31191
1
如果您直接使用大多数提供的答案,它们将以类似于n^2 * log(n)的时间运行。您应该进行优化,确保您的浮点数首先出现在子列表中,并采用使用第一个元素的快捷方式,以免每次都要搜索列表。 - Wug
@Wug 确实,我相信在另一个算法中肯定有一种方法可以做到这一点。但是对于小数据系列来说,这种效率是否相关呢?目前情况下,每个子列表可能不会超过50个值(很少会这么高),而且子列表数量也不到15个。我以前学习算法效率时得出的结论是,对于像这样的小数据量,即使大O效率更好,我也只能节省几毫秒的时间。 - zakparks31191
对于小数据集,这可能无关紧要。但对于包含大约一百个元素的一百个列表的任何内容,您可能会看到明显的差异。 - Wug
好的,这正是我想的,不过还是谢谢你澄清了。 - zakparks31191
6个回答

9

sort方法有一个方便的key关键字参数,它允许您指定要调用的函数来确定列表应按什么信息排序。

对列表进行排序就像编写一个返回每个子列表中包含的浮点值的函数一样容易:

def sortOnFloat(sublist):
    return [v for v in sublist if isinstance(v, float)]

请注意,我只返回所有浮点数值的一个列表;这比只返回一个要容易得多。即使子列表中没有浮点值,这也可以工作。
像这样对列表进行排序:
listed.sort(key=sortOnFloat)

我已经克隆了您的示例,并使用上述方法进行了更新:http://ideone.com/u8ufK 生成的输出:
['1 BW', '1AW AS', '3E FZ', '1BWAK', 'POK', 'TESTK', '1-2EHZ', '2E AK', 1.0]
['1 NWZ', '1 RWZ', '2 NWZ', '2 RWZ', '1E HZ', '1W HZ', '1-2EHZ', 2.0, '2W HZ']
['1 NWZ', '1W HZ', '3E FZ', 'SNOK', 'POK', 3.0, '1-2EHZ', '2E AK', '2W HZ']

请注意,.sort() 方法是就地排序列表。您还可以使用 sorted() 函数 生成已排序的新列表;它接受相同的参数:
orderedlist = sorted(listed, key=sortOnFloat)

但请注意,原地排序始终更快。


太棒了,我会测试一下并在之后回复你。另外感谢你对sort和sorted之间简单的区别解释,我以前从未意识到它们有所不同! - zakparks31191
非常好!非常感谢!这比在字典中循环要简单得多。 - zakparks31191

2
创建一个函数来提取您想要排序的键,并调用 sorted
listed = [ ["1 NWZ", "1 RWZ", "2 NWZ", "2 RWZ", "1E HZ", "1W HZ", "1-2EHZ", 2.0, "2W HZ"],
["1 NWZ", "1W HZ", "3E FZ", "SNOK", "POK", 3.0, "1-2EHZ", "2E AK", "2W HZ"],
["1 BW", "1AW AS", "3E FZ", "1BWAK", "POK", "TESTK", "1-2EHZ", "2E AK", 1.0]] 

def get_key(l):
    return next(e for e in l if type(e) is float)

print sorted(listed, key=get_key)

1

这是一个很棒的链接,我相信将来我会用到它。谢谢! - zakparks31191

0

你会遇到错误,因为列表中的数字是浮点数,但你使用整数查找键:

listed = [ ["1 NWZ", "1 RWZ", "2 NWZ", "2 RWZ", "1E HZ", "1W HZ", "1-2EHZ", 2.0, "2W HZ"],
["1 NWZ", "1W HZ", "3E FZ", "SNOK", "POK", 3.0, "1-2EHZ", "2E AK", "2W HZ"],
["1 BW", "1AW AS", "3E FZ", "1BWAK", "POK", "TESTK", "1-2EHZ", "2E AK", 1.0]]

dictionary={}
for sub_list in listed:
    for value in sub_list:
        if isinstance(value,float):  #### you look for floats
            dictionary[str(value)]=sub_list   ### the key is created as string
        else:
            pass
ordered_list=[]
for i in range(1,len(listed)+1):   ### this is a range of INTS!!!!
    if dictionary[str(i)]:
        ordered_list.append(dictionary[str(i)])  #### str(i) is '1', not '1.0' 

for sub_list in ordered_list:
    print sub_list

我只能想到这不是好的代码。首先,在同一个列表内不应该混合字符串和数字。如果您要创建该列表,我建议您使用字典,例如:

listitem = {'number': 2.0, 'strings': ['1 NHZ', '1 RWZ', 'TESTK']}

希望这能帮助到你!


0
>>> listed = [ ["1 NWZ", "1 RWZ", "2 NWZ", "2 RWZ", "1E HZ", "1W HZ", "1-2EHZ", 2.0, "2W HZ"],
["1 NWZ", "1W HZ", "3E FZ", "SNOK", "POK", 3.0, "1-2EHZ", "2E AK", "2W HZ"],
["1 BW", "1AW AS", "3E FZ", "1BWAK", "POK", "TESTK", "1-2EHZ", "2E AK", 1.0]]
>>> listed
[['1 NWZ', '1 RWZ', '2 NWZ', '2 RWZ', '1E HZ', '1W HZ', '1-2EHZ', 2.0, '2W HZ'], ['1 NWZ', '1W HZ', '3E FZ', 'SNOK', 'POK', 3.0, '1-2EHZ', '2E AK', '2W HZ'], ['1 BW', '1AW AS', '3E FZ', '1BWAK', 'POK', 'TESTK', '1-2EHZ', '2E AK', 1.0]]
>>> dictionary ={}
>>> for index,sub_list in enumerate(listed):
    for value in sub_list:
        if isinstance(value,float):
            dictionary[value]=index
        else:
            pass


>>> dictionary
{1.0: 2, 2.0: 0, 3.0: 1}
>>> it = sorted(dictionary.items())
>>> it
[(1.0, 2), (2.0, 0), (3.0, 1)]
>>> ordered_list = []
>>> for item in it:
    ordered_list.append(listed[item[1]])


>>> ordered_list
[['1 BW', '1AW AS', '3E FZ', '1BWAK', 'POK', 'TESTK', '1-2EHZ', '2E AK', 1.0], ['1 NWZ', '1 RWZ', '2 NWZ', '2 RWZ', '1E HZ', '1W HZ', '1-2EHZ', 2.0, '2W HZ'], ['1 NWZ', '1W HZ', '3E FZ', 'SNOK', 'POK', 3.0, '1-2EHZ', '2E AK', '2W HZ']]
>>> 

0
你的错误是因为代码中没有'1'元素。实际上应该是'1.0'(因为它是浮点数),这样做可以使代码正常工作:
for i in range(1,len(listed)+1):
    if dictionary[str(float(i))]:
        ordered_list.append(dictionary[str(float(i))])

然而,依我之见,这远非是一种好的方式来实现你所尝试做的事情,许多人提供了很好的替代建议。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接