如何根据嵌套列表中的每个元素对嵌套列表进行排序

时间:2016-09-29 18:54:14

标签: python django sorting nested-lists

我有一个模型页面,它存储一个可选的父页面(自身的实例)。在我的观点中,我创建了一个函数,它将返回所有页面及其父级的嵌套列表。

例如,我的页面架构是

CCC
  AAA
    DDD
    KKK
      EEE
ZZZ
  BBB

所以DDD有父页面AAA,它拥有自己的父页面CCC。 CCC是首页,没有父页面。

该函数将首先获取所有Pages实例的查询集,并按字母顺序对它们进行排序。然后它将继续递归地生成“完整父架构”列表,其中该列表上的每个元素是所有父页面的另一列表,包括页面本身。从上面的示例中,如果我们为页面DDD获取一个列表,它将返回[CCC,AAA,DDD]。

我的函数当前为上述示例返回一个这样的列表:

[ 
  [CCC, AAA],
  [ZZZ, BBB],
  [CCC],
  [CCC, AAA, DDD],
  [CCC, AAA, KKK, EEE],
  [CCC, AAA, KKK],
  [ZZZ],
]

从该列表中可以看出,所有元素都按照该列表中的最后一个元素按字母顺序排序。现在我想在我的前端显示所有那些父页面,基本上看起来像一个站点地图,并显示我站点上所有页面的正确父架构,根据每个嵌套列表中的每个元素按字母顺序排序。最终结果将是:

[ 
  [CCC],
  [CCC, AAA],
  [CCC, AAA, DDD],
  [CCC, AAA, KKK],
  [CCC, AAA, KKK, EEE],
  [ZZZ],
  [ZZZ, BBB],
]

简单来说,我希望浏览每个列表中的每个第一个元素并按字母顺序对其进行排序,然后对每个第二个元素进行排序,然后对它们进行排序,然后是第三个,然后是第四个,依此类推。有没有办法做到这一点?

编辑: 为避免混淆,我的观点是:

def page_list(request):


    # Fetch all pages and sort them alphabetically
    queryset = Page.objects.all().order_by("title")
    output = []

    # Generate list of pages and their parents
    for page in queryset:
        output.append(get_list_of_parents(page))

    context = {
        "title": "Page List",
        "page_list": output,
    }

    return render(request, template + '/page_list.html', context)

# Get an array of all parent instances of a Page model
def get_list_of_parents(page, list=None):

    current_page = page 
    parent_list = []    

    if list is not None:
        parent_list = list

    parent_list.append(current_page)

    if current_page.parent is not None:
        parent_list = get_list_of_parents(current_page.parent, parent_list)
    else:
        # if this is the last parent page, reverse the order of list to display list in form of parent path to child
        parent_list.reverse()

    return parent_list

2 个答案:

答案 0 :(得分:0)

使用Pages树:

我定义了这个简单的树结构:

class Page(object):
    def __init__(self, name, children=None):
        self.name = name
        self.children = children or []

    def display(self, indent=""):
        child_repr = [child.display(indent=indent + "  ") for child in self.children]
        return indent + self.name + "\n" + "".join(child_repr)

    def __str__(self):
        return self.display()

display__str__方法用于打印。

我可以将您的树构建为Pages列表:

tree = [
    Page("CCC", [
        Page("AAA", [
            Page("DDD"),
            Page("KKK", [
                Page("EEE")])])]),
    Page("ZZZ", [
        Page("BBB")])]

我可以显示如下结构:

for item in tree:
    print(item)

我明白了:

CCC
  AAA
    DDD
    KKK
      EEE

ZZZ
  BBB

要遍历树,我定义了以下方法:

    def traverse(self, result, stack=None):
        stack = stack or []
        stack.append(self.name)
        result.append(list(stack))
        for child in self.children:
            child.traverse(result, stack)
        stack.pop()

result是要填写的列表。

用法:

result = []
for item in tree:
    item.traverse(result)

import pprint

pprint.pprint(result)

我会得到:

[['CCC'],
 ['CCC', 'AAA'],
 ['CCC', 'AAA', 'DDD'],
 ['CCC', 'AAA', 'KKK'],
 ['CCC', 'AAA', 'KKK', 'EEE'],
 ['ZZZ'],
 ['ZZZ', 'BBB']]

大!

答案 1 :(得分:0)

利用itertools中的辅助函数,并使用简单高效的单行比较函数进行排序。

>>> import pprint
>>> from itertools import dropwhile, izip_longest
>>> pages = [['CCC', 'AAA'],
...          ['ZZZ', 'BBB'],
...          ['CCC'],
...          ['CCC', 'AAA', 'DDD'],
...          ['CCC', 'AAA', 'DDD', 'EEE'],
...          ['CCC', 'AAA', 'KKK'],
...          ['ZZZ']]
>>> pprint.pprint(sorted(pages, cmp=lambda a, b: cmp(*next(dropwhile(lambda x: not cmp(x[0], x[1]), izip_longest(a, b))))))
[['CCC'],
 ['CCC', 'AAA'],
 ['CCC', 'AAA', 'DDD'],
 ['CCC', 'AAA', 'DDD', 'EEE'],
 ['CCC', 'AAA', 'KKK'],
 ['ZZZ'],
 ['ZZZ', 'BBB']]
>>>

这不仅适用于字符串,也适用于Page实例,只要它们具有可比性,即您已在Page类中定义了__cmp__方法。