Я использую словарь Python (product_dict) для представления иерархии продукта и всех его частей. Ключи dict - это уникальные идентификаторы (UUID), а значения - это объекты класса, содержащие всю информацию об этих частях, включая:

part.name        # A string, containing the actual name of a component
part.idCode      # UUID of component
part.parent      # UUID of parent component
part.children    # List of UUIDs of child components
part.tier        # An integer that specifies its tier/level within the hierarchy

Теперь, с целью упорядоченного вывода данных, я хочу отсортировать части как в иерархическом, так и в алфавитном порядке. Для иерархической сортировки с использованием древовидной структуры я нашел ответ на этот вопрос, который отлично подходит для печати: Сортировка данных иерархически < / а>. Чтобы этот пример работал с моей структурой данных, я внес несколько небольших изменений:

class Node:
    def __init__(self, article):
        self.article = article
        self.children = []
        self.parent = None
        self.name = None 

    def printer(self, level=0):
        print ('{}{}'.format('\t' * level, self.name))
        for child in self.children:
            child.printer(level + 1)


class Tree:
    def __init__(self):
        self.nodes = {}

    def push(self, article, parent, name):                          
        if parent not in self.nodes:
            self.nodes[parent] = Node(parent)
        if article not in self.nodes:                              
            self.nodes[article] = Node(article)
        if parent == article:
            return
        self.nodes[article].name = name
        self.nodes[article].parent = self.nodes[parent]             
        self.nodes[parent].children.append(self.nodes[article])    

    @property
    def roots(self):
        return (x for x in self.nodes.values() if not x.parent)


t = Tree()

for idCode, part in product_dict.iteritems(): 
    t.push(idCode, part.parent, part.name)
for node in t.roots:
    node.printer()

Рассматривая пример моего продукта, являющегося самолетом, результат теперь выглядит следующим образом (фактический порядок варьируется):

Aircraft
    Systems
        Subsystem 2
        Subsystem 1
            Subsubsystem 1.1
    Engines
    Airframe
        Section 2
        Section 1
        Section 4
        Section 3

Однако из-за моего ограниченного понимания Python на данном этапе я изо всех сил пытаюсь добавить в эту процедуру сортировку по алфавиту (на основе строк part.name). Я понимаю, как строится дерево, но не понимаю процедуры печати и поэтому не могу судить, где добавить процедуру сортировки по алфавиту.

В данном примере мой желаемый результат должен быть:

Aircraft
    Airframe
        Section 1
        Section 2
        Section 3
        Section 4
    Engines     
    Systems
        Subsystem 1
            Subsubsystem 1.1
        Subsystem 2

Любая помощь приветствуется. Я не придерживаюсь приведенного выше метода иерархической сортировки, поэтому открыт для совершенно разных подходов.

0
Fulco 9 Янв 2014 в 19:55

2 ответа

Лучший ответ

Похоже, что единственное, что вам нужно сделать, это отсортировать дочерние элементы по имени при печати, т.е.

 for child in sorted(self.children, key = lambda x: x.name):
        child.printer(level + 1)
1
dornhege 9 Янв 2014 в 16:02

Учитывая иерархический словарь:

{
    UUID("71f0967f-bfd3-43d5-883e-f3c971de141f"): {
        "id": UUID("71f0967f-bfd3-43d5-883e-f3c971de141f"),
        "name": "D10:0:0",
        "code": "r0:0:0",
        "level": 0,
        "parent_id": None,
    },
    UUID("f3dcaf21-66c9-48c5-9aae-f9ac84fc7d45"): {
        "id": UUID("f3dcaf21-66c9-48c5-9aae-f9ac84fc7d45"),
        "name": "D11:0:0",
        "code": "r1:0:0",
        "level": 1,
        "parent_id": UUID("71f0967f-bfd3-43d5-883e-f3c971de141f"),
    },
    UUID("4c39d1e8-ba09-455c-8f76-866200531c51"): {
        "id": UUID("4c39d1e8-ba09-455c-8f76-866200531c51"),
        "name": "D12:0:0",
        "code": "r2:0:0",
        "level": 2,
        "parent_id": UUID("f3dcaf21-66c9-48c5-9aae-f9ac84fc7d45"),
    },
    UUID("8c4e89f2-7564-417f-88ba-1cbb3f9ac23f"): {
        "id": UUID("8c4e89f2-7564-417f-88ba-1cbb3f9ac23f"),
        "name": "D12:0:1",
        "code": "r2:0:1",
        "level": 2,
        "parent_id": UUID("f3dcaf21-66c9-48c5-9aae-f9ac84fc7d45"),
    }, ...
}

Вы можете сортировать по ключу, сохраняя иерархию:

TD1 = typing.Dict[str, typing.Union[UUID, str, int, None]]
TD1Dict = typing.Dict[UUID, TD1]
def _sort_dict_hierarchy(dicts: TD1Dict, parent_id: typing.Optional[UUID] = None) -> TD1Dict:
    roots = [(k, v) for k, v in dicts.items() if v['parent_id'] == parent_id]
    sorted_dicts: TD1Dict = {}
    for k, v in sorted(roots, key=lambda r: r[1]['name']):
        sorted_dicts[k] = v
        sorted_dicts.update(_sort_dict_hierarchy(dicts, v['id']))
    return sorted_dicts

Тесты:


def create_dict_hierarchy(parent_id=None, level=0, pos=0, max_level=4):
    """Create a hierachy of dicts as we expect to be returned from oauth2."""
    dicts = {}
    for i in range(random.randrange(2, 4)):
        uid = uuid.uuid4()
        dicts[uid] = {
            'id': uid,
            'name': f'D1{level}:{pos}:{i}',
            'code': f'r{level}:{pos}:{i}',
            'level': level,
            'parent_id': parent_id,
        }
        if level < max_level:
            dicts.update(create_dict_hierarchy(uid, level+1, i, max_level))
    return dicts


def test_sort_dict_hierarchy():
    """Sort dicts by nane in hirarchy."""
    dicts = create_dict_hierarchy(max_level=3)
    dicts_items = list(dicts.items())
    random.shuffle(dicts_items)
    shuffled_dicts = {k: v for k, v in dicts_items}
    assert list(dicts.keys()) != list(shuffled_dicts.keys())

    sorted_dicts = _sort_dict_hierarchy(shuffled_dicts)

    assert list(dicts.keys()) == list(sorted_dicts.keys())

0
cleder 3 Дек 2020 в 15:09