扁平优于嵌套" - 对数据和代码都是如此吗?

35 投票
6 回答
16174 浏览
提问于 2025-04-16 08:09

这篇问题让我思考:我们是否应该把“扁平化比嵌套更好”的原则应用到数据上,而不仅仅是代码?即使数据本身有一个“逻辑树结构”呢?

在这种情况下,我想这意味着用一个ID的列表来表示子节点,而不是实际的子节点列表,把所有节点放在一个单一的列表里:

[ {'id': 4, 'children': ()},
  {'id': 2, 'children': (1, 7)},
  {'id': 1, 'children': (6, 5)},
  {'id': 6, 'children': ()},
  {'id': 5, 'children': ()},
  {'id': 7, 'children': (3,)},
  {'id': 3, 'children': ()} ]

(我使用元组是因为我不想给自己太多修改对象的灵活性,直到这种灵活性证明是有用的并且可以清晰使用。无论如何,我在这里绝对不会用None来代替空序列,因为那样会让逻辑变得复杂,而且“特殊情况并不够特殊”——在这里,它根本就不特殊。)

这样确实更简短,但树结构就变得不明显了。这是不是和“明确比隐含更好”相矛盾呢?

就我个人而言,我觉得“扁平化比嵌套更好”的适用性有限,远不是禅宗中最重要的方面。(当然,如果我不允许自己有一定的嵌套,我就无法做很多不错的函数式编程的事情。)我怀疑“嵌套”的问题在于,当你理解信息时需要切换上下文。我真的认为这个问题在遵循命令式逻辑时更明显,而在解析数据或函数式代码时就简单多了——在那种情况下,你可以更容易地给嵌套的部分起个名字,并把它的工作与外部上下文分开考虑。

你怎么看?

6 个回答

10

我们是否应该把“扁平比嵌套好”的原则也应用到数据上,而不仅仅是代码呢?

不应该。

即使数据有一个“逻辑树结构”呢?

这就是为什么“扁平比嵌套好”这个原则不适用于数据,只适用于代码。

...树结构变得不清晰。这是不是和“显式比隐式好”相矛盾呢?

这根本没法比较。“扁平树”是一种常见的SQL实现,因为SQL无法处理真正树形结构的无限递归。

把Python的哲学和数据结构设计拿来比较是没有意义的。这两者就像数字“2”和把一块奶酪分成“2”块一样,根本没法比。一个是事物,另一个是动作。

数据结构是事物。

Python描述的是动作。

13

这个问题完全是主观的。答案是:“这要看情况。”

这取决于你数据的主要用途。如果你经常需要引用嵌套结构,那么用这种方式表示数据是有道理的。如果你除了在构建嵌套结构时根本不使用平面结构,那为什么还要保留平面结构呢?

所谓的“平面”表示法是关系数据库模型的基础之一:每种类型的数据都存在于专门的表中,而这些数据之间的关系则放在不同的表里。这种方式很有用,但在代码中有时会比较难处理。另一方面,处理某种特定类型的所有数据则非常简单。

举个例子,如果我想找到你示例数据中id为2的记录的所有后代。如果数据已经是层级结构(也就是说,原生表示是“嵌套”结构),那么找到id为2的记录并遍历它的子记录、孙记录等就非常简单。

但是,如果原生表示是你展示的那种顺序结构,那么我就得遍历整个数据集来创建层级结构,然后再找到记录2及其子记录。

所以,正如我所说的,“这要看情况。”

8

我其实对这两种方式没有特别的偏好,主要是看哪个更适合具体的任务。

如果结构很重要,使用嵌套的方式会让事情变得简单。如果你经常需要处理每一个节点,平坦的结构就能让你很方便地用 for node in tree 来操作。当然,如果你自己定义一个类,可以很容易地让这两种方式都变得简单;不过在和外部系统打交道时,比如转换成JSON格式,可能会比较麻烦。

撰写回答