【问题标题】:Building a list from positional relationships between the elements从元素之间的位置关系构建列表
【发布时间】:2014-01-28 22:00:22
【问题描述】:

如何从一组项目中形成一个扁平的有序列表,每个项目都可能要求它们出现在列表中的其他项目之前和/或之后?

Sample input
-----------------------
3: before 5 and after 2
8: before 5
2: before 3
5: no constraint

Sample output
-------------
[2, 3, 8, 5]

显然,这类问题的一般解决方案是非唯一的(考虑许多没有约束的元素的情况),这很好 - 任何满足约束的结果都可以。

我也知道这里有很多错误情况(重复元素,两个元素都想在彼此之前,等等......)。现在我对“快乐路径”感兴趣——稍后我会添加错误处理。

这里有几个 Python 测试用例。它们远非全面,但应该足以让您了解:

def test_some_unconstrained_elements():
    l = ListBuilder()
    l.add(1, after=None, before=None)
    l.add(7, after=None, before=None)
    assert set(l.to_list()) == {1, 7}

def test_element_which_should_appear_after_already_added_element():
    l = ListBuilder()
    l.add(5, after=None, before=None)
    l.add(3, after=5, before=None)
    assert l.to_list() == [5, 3]

def test_element_which_should_appear_after_element_added_later():
    l = ListBuilder()
    l.add(3, after=5, before=None)
    l.add(5, after=None, before=None)
    assert l.to_list() == [5, 3]

def test_element_which_should_appear_between_two_already_added_elements():
    l = ListBuilder()
    l.add(4, after=None, before=None)
    l.add(2, after=None, before=None)
    l.add(6, after=2, before=4)
    assert l.to_list() == [2, 6, 4]

def test_two_elements_either_side_of_new_element():
    l = ListBuilder()
    l.add(4, after=6, before=None)
    l.add(2, after=None, before=6)
    l.add(6, after=None, before=None)
    assert l.to_list() == [2, 6, 4]

def test_element_which_should_appear_after_missing_element():
    l = ListBuilder()
    l.add(4, after=6, before=None)
    assert l.to_list() == [4]

def test_two_elements_which_should_appear_after_the_same_element():
    l = ListBuilder()
    l.add(4, after=None, before=None)
    l.add(6, after=4, before=None)
    l.add(8, after=4, before=None)
    assert l[0] == 4
    assert set(l[1:]) == {6, 8}

def test_fully_constrained_short_list():
    l = ListBuilder()
    l.add(3, after=4, before=None)
    l.add(4, after=5, before=3)
    l.add(5, after=None, before=4)
    assert l.to_list() == [5, 4, 3]

注意。 这不是家庭作业。这是我在现实生活中需要解决的一个实际问题(我正在研究a test framework;我很乐意详细说明我需要它做什么),但我不够聪明:(

【问题讨论】:

  • 2: before 3 | 8 正确吗?
  • 到目前为止,除了测试用例之外,您还做了什么?
  • @rendon 抱歉,我认为我的示例输入/输出表的格式有点误导。我会改的。
  • 您在示例中使用了数字。对列表进行排序不是一种选择吗?
  • 这似乎是一种拓扑排序。这种排序通常用于项目计划中以安排活动。我说的对吗?

标签: python algorithm list


【解决方案1】:

这看起来像一个拓扑排序,所以从某个地方(例如here)获取一个实现并修改您的数据格式以使用它。例如:

def toposort2(data):
    # modified from http://rosettacode.org/wiki/Topological_sort#Python
    for k, v in data.items():
        v.discard(k) # Ignore self dependencies
    extra_items_in_deps = reduce(set.union, data.values()) - set(data.keys())
    data.update({item:set() for item in extra_items_in_deps})
    while True:
        ordered = set(item for item,dep in data.items() if not dep)
        if not ordered:
            break
        for x in sorted(ordered):
            yield x
        data = {item: (dep - ordered) for item,dep in data.items()
                if item not in ordered}
    if data:
        raise ValueError("a cyclic dependency exists")

def toposort_wrap(data):
    dep_dict = {}
    for d in data:
        for bef in d.get("before", ()):
            dep_dict.setdefault(bef, set()).add(d["value"])
        dep_dict.setdefault(d["value"], set()).update(d.get("after", ()))
    print dep_dict
    result = list(toposort2(dep_dict))
    return result

之后我们有

>>> data = [dict(value=3, before=(5,), after=(2,)),
...         dict(value=8, before=(5,)),
...         dict(value=2, before=(3,)),
...         dict(value=5)]
>>> toposort_wrap(data)
{8: set([]), 2: set([]), 3: set([2]), 5: set([8, 3])}
[2, 8, 3, 5]

(未经测试,所以概念验证比其他任何东西都多,但这就是我要做的事情。)

【讨论】:

  • +1 提到了获取现有实现的好处。
  • 我最终使用了不同的拓扑排序实现(维基百科有两种),因为它似乎更适合我的数据形状。但如果没有你的回答,我不会知道谷歌是为了什么。非常感谢! :)
【解决方案2】:

拓扑排序似乎是一个很好的解决方案。该图可能如下所示:列表的每个元素都是节点。如果 a 在 b 之前,则存在从 b 到 a 的有向边。

【讨论】:

    猜你喜欢
    • 2017-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多