P128: Sorting a list of lists according to length of sublists
按照子列表长度排序包含列表的列表。本题要实现两种排序:按子列表长度排序和按子列表长度在全列表中的频率排序。
照例还是先写测试用例:
from python99.lists.p128 import lsort, ifsort
def test_lsort():
assert lsort([[1, 2, 3], ['a', 'b'], [4]]) == [[4], ['a', 'b'], [1, 2, 3]]
def test_ifsort():
assert ifsort([[1, 2, 3], [4, 5, 6], [7, 8, 9], ['a'], ['b'], ['c', 'd']]) == [
['c', 'd'], ['a'], ['b'], [1, 2, 3], [4, 5, 6], [7, 8, 9]]
先解第一个「按子列表长度排序」。首先,将每个子列表转换成列表和长度组成的二元组。这个可以使用List Comprehension实现。 List comprehension的形式为:
[f(x) for x in l]
- f为对映函数,其可为普通Python函数,也可为表达式
- x为局部变量,用于引用每一个元素
- l输入序列
本例中,f
为二元组构造表达式(e, len(e))
。
然后,使用内建的排序函数sorted
排序。sorted
可以通过lambda表达式自定义排序所基于的键。
最后,再把排好序的列表中的每一个二元组拆包,析出子列表。
代码实现:
# Sorting a list of lists according to length of sublists
# a) We suppose that a list (Inlist) contains elements that are lists themselves.
# The objective is to sort the elements of InList according to their length.
# E.g. short lists first, longer lists later, or vice versa.
import functools
def lsort(l):
return [l_and_length[0] for l_and_length in sorted([(e, len(e)) for e in l], key=lambda x: x[1])]
再解第二个「按子列表长度在全列表中的频率排序」。首先,把列表中的每一个元素「子列表」转换为「子列表和长度频率」二元组。这其中先读取子列表长度,再使用「字典(dictionary)」和「归纳(reduce)」统计长度频率,最后构造「子列表和长度频率」二元组。
然后,使用内建的排序函数sorted
排序。
最后,把排好序的列表中的二元组拆包,析出子列表。
代码实现:
# b) Again, we suppose that a list (InList) contains elements that are lists themselves.
# But this time the objective is to sort the elements of InList according to their length frequency;
# i.e. in the default, where sorting is done ascendingly, lists with rare lengths are placed first,
# others with a more frequent length come later.
def ifsort(l):
list_with_length = [(e, len(e)) for e in l]
lengths = [e[1] for e in list_with_length]
length_frequency = functools.reduce(accum_to_dict, lengths, {})
list_with_length_frequency = [
(e[0], length_frequency[e[1]]) for e in list_with_length]
return [e[0] for e in sorted(
list_with_length_frequency, key=lambda x: x[1])]
def accum_to_dict(d, value):
if value not in d:
d[value] = 1
else:
d[value] = d[value]+1
return d