【问题标题】:What is an efficient algorithm for extracting bags from lists of pairs?从对列表中提取包的有效算法是什么?
【发布时间】:2011-04-28 18:59:27
【问题描述】:

我有一个对象对列表。对象可以按任意顺序出现在对中。找到相同对象之间的所有包(即允许重复的集合)的最有效算法(和实现?)是什么。出于我的目的,可以假定对象引用是指针、名称或一些类似的方便、简短、有用的表示。各个对是可识别的。在对的两个部分中没有具有相同对象的对。

所以给定一个对的列表(Oid 是一个对象引用;Pid 是一个对引用)

O1-P1-O2
O3-P2-O4
O5-P3-O1
O1-P4-O2
O2-P5-O1
O1-P6-O5
O7-P7-O8

应该返回:

P1;P4;P5 and P3;P6

【问题讨论】:

  • 你试过什么?一个简单的字典/哈希直方图(由数组支持)可以正常工作,或者多地图也可以正常工作。总是在稳定有序的对上进行索引。
  • 我认为这取决于实施限制。也就是说,如果我们处理的是字符串,而不是可以直接处理三个组件的对象。理想情况下,您只需对对象进行规范化,这样您就可以对列表进行排序(例如,如果最低值的对象首先出现)并从那里开始。
  • 我在这个问题中强调了效率,因为检查行李必须在内部循环中完成;需要在大名单上完成;并且列表中与检查直接相关的部分将经常更改。
  • 这是我希望我能接受多个答案的场合之一。所有的答案都非常有用;非常有帮助,相关且发人深省。谢谢。

标签: performance algorithm list bag


【解决方案1】:

花哨的术语可能会让这个问题看起来很困难,但实际上很简单。

  1. 对每对中的元素进行排序。 (既然你说对象可以表示为数字,我们假设pair.first <= pair.second总是)
  2. 排序列表,使用传统方式比较对。 IE。 pair1 < pair2 表示 pair1.first < pair2.firstpair1.first == pair2.first && pair1.second < pair2.second

您示例中的排序列表将如下所示

O1-P1-O2
O1-P4-O2
O1-P5-O2
O1-P3-O5
O1-P6-O5
O3-P2-O4
O7-P7-O8

现在一个“袋子”中的所有元素都将占据列表中的连续位置。来吧,抓住它们。

也有使用哈希解决这个问题的选项。

【讨论】:

  • 谢谢你。您的方法是否涉及至少三遍数据。如果是这样,这并不像我希望的那样有效 - 请参阅我对效率的评论。
  • @Chris Hashtables,然后。它将为您提供线性解决方案,如果仔细实施,只会增加一点内存消耗。
  • 我已经用 Python 实现了你的答案。 stackoverflow.com/questions/3990737/…
【解决方案2】:

您的对象是否定义了“小于”? 如果是这样,那么您只需遍历您的配对列表即可完成此操作。

1) 创建一个空的包集合,由两个“对象”参数索引。按照惯例,第一个索引参数应该小于第二个索引参数。

2) 循环遍历列表,在 min(pair.left,pair.right), max(pair.left, pair.right) 处找到合适的包索引。将元素添加到该包中。

【讨论】:

  • 我的对象目前没有小于定义的,但这是一个可以很容易合并的细节。这看起来是我正在寻找的那种方法,只涉及一次数据传递。我将更详细地研究这一点。鉴于大型列表中的一小部分将迅速变化,但我最感兴趣的是我正在尝试做的事情,是否有更有效的方法来解决这个问题?
  • 如果你从 List 复制 N 项到 Bags 集合中,那么运行时间将至少为 O(N)。
  • 谢谢。在 cmets 之间,我意识到我可以通过采用您的方法来提高效率,但预先计算袋子的收集;并且只重复计算变化部分。仍然是 O(n) 但 n 大大减少了。再次感谢。
  • 我已经用 Python 实现了你的答案。 stackoverflow.com/questions/3990737/…
【解决方案3】:

@Nikita Rybak's solution 在 Python 中使用 itertools.groupby():

#!/usr/bin/env python
from itertools import groupby

pairs = """
O1-P1-O2
O3-P2-O4
O5-P3-O1
O1-P4-O2
O2-P5-O1
O1-P6-O5
O7-P7-O8
""".split()

def lex_order(pair):
    """'O2-P5-O1' -> ['01', '02']"""
    return sorted(pair.split('-')[::2])

data = sorted(pairs, key=lex_order)
for key, group in groupby(data, key=lex_order):
    print "key=%(key)s, pairs=%(pairs)s" % dict(key=key, pairs=list(group))

输出:

key=['O1', 'O2'], pairs=['O1-P1-O2', 'O1-P4-O2', 'O2-P5-O1']
key=['O1', 'O5'], pairs=['O5-P3-O1', 'O1-P6-O5']
key=['O3', 'O4'], pairs=['O3-P2-O4']
key=['O7', 'O8'], pairs=['O7-P7-O8']

@mbeckish's solution 在 Python 中:

#!/usr/bin/env python
from collections import defaultdict

pairs = """
O1-P1-O2
O3-P2-O4
O5-P3-O1
O1-P4-O2
O2-P5-O1
O1-P6-O5
O7-P7-O8
""".split()

bags = defaultdict(list)
for pair in pairs:
    i, _, j = pair.split('-') # 'O2-P5-O1' -> ['02', 'P5', '01']
    bags[min(i,j), max(i,j)].append(pair)

import pprint;
pprint.pprint(dict(bags))

输出:

{('O1', 'O2'): ['O1-P1-O2', 'O1-P4-O2', 'O2-P5-O1'],
 ('O1', 'O5'): ['O5-P3-O1', 'O1-P6-O5'],
 ('O3', 'O4'): ['O3-P2-O4'],
 ('O7', 'O8'): ['O7-P7-O8']}

【讨论】:

  • 我理解切片技巧的作用 ([::2]) 但你能告诉我它的术语是什么吗?我想阅读更多关于它的内容。
  • @jlv: "extended slices": a[i:j:k] 选择索引为xa 的所有项,其中x = i + n*kn >= 0i <= x < j docs.python.org/reference/datamodel.html 阅读了解@987654335 @、slice()numpy 数组用于高级用法。
猜你喜欢
  • 2020-02-13
  • 2011-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多