将具有相互元素的所有子数组合并为一个子数组

时间:2010-01-20 03:59:35

标签: python performance algorithm arrays

我需要找到共享任何相互元素的所有子数组并将它们合并为一个子数组。 (用Python实现,但任何算法思想都会有所帮助)

多维数组结构:

categories = {'car':['automobile','auto'],
             'bike':['vehicle','motorcycle','motorbike','automobile'],
             'software':['computer','macbook','apple','microsoft','mozilla'],
             'firefox':['internet','mozilla','browser']
             'bicycle':['vehicle']}

我想将'car','bike'和'bicycle'合并到一个列表中(保留第一个列表的键新列表的键可以是任何相关键)和'software '和'firefox'也合并到一个列表中。

表现至关重要。

到目前为止,我可以提供的最佳解决方案是维持元素的扁平一维数组 => list_key (例如'汽车'=>'汽车')然后为多维数组中的每个列表运行以下递归函数(伪代码):

function merge_similar(list_key):
    For each element in categories[list_key]:
        If flatten_array.has_key(element):
            list_to_merge = flatten_array[element]
            merge_similar(list_to_merge) /* merge other lists which share an element with our newly found similar list */
            categories[list_key] = merge(categories [list_key], categories[list_to_merge])
            delete categories[list_to_merge]

知道如何改善它的性能吗?

谢谢!

3 个答案:

答案 0 :(得分:2)

请注意, 没有“第一个键” - dicts不保持顺序,因此如果您需要保留一些订单,则需要从一些不同的替代数据结构开始。< / p>

除了与订单相关的问题外,我还会从以下内容开始:

def merged(dictoflists):
  result = dict()
  reversed = dict()
  for k, l in dictoflists.iteritems():
    intersecting = set(reversed.get(w) for w in l) - set([None])
    if intersecting:
      pickone = intersecting.pop()
      into = result[pickone]
    else:
      pickone = k
      into = result[k] = set()
    for ok in intersecting:
      into.update(result.pop(ok))
    into.update(l)
    for w in into:
      reversed[w] = pickone
  return dict((k, sorted(l)) for k, l in result.iteritems())

如果订单对您很重要,set的使用会有问题,您需要更复杂(和更慢)的数据结构 - 但是,如果是这种情况,您应该首先详细说明确切地说,在可能发生的各种可能情况下,您需要遵守哪些排序限制。

答案 1 :(得分:0)

我无法想象递归解决方案会很快 使用list.extend()太慢了吗? 你可以这样做:

categories['car'].extend(categories['bike']);
categories['car'].extend(categories['bicycle']);

或者更为一般,如果您传入要合并的键列表:

first_key=None;
for key in keys_whose_lists_I_want_to_merge:
    if first_key is None:
        first_key=key;
    else:
        categories[first_key].extend(categories[key]);

如果要合并大量列表,可以优化该循环,以便在第一次之后不执行“无”检查。请参阅Python Performance Tips页面上标题为“在运行时重新映射函数”的提示。

答案 2 :(得分:0)

>>> categories = {'car':['automobile','auto'],
             'bike':['vehicle','motorcycle','motorbike','automobile'],
             'software':['computer','macbook','apple','microsoft','mozilla'],
             'firefox':['internet','mozilla','browser'],
             'bicycle':['vehicle']}
>>> # Use sets for values
>>> for k,v in categories.items(): categories[k] = set(v)

>>> # Acumulate
>>> for k1, v1 in categories.items():
    if v1:
        for k2,v2 in categories.items():
            if v2 and k1 != k2 and v1 & v2:
                v1 |= v2
                categories[k2] = None
        categories[k1] = v1


>>> # Print
>>> for k1, v1 in categories.items():
    if v1: print('%s: %r' %(k1,v1))


bicycle: {'motorbike', 'vehicle', 'auto', 'automobile', 'motorcycle'}
firefox: {'apple', 'mozilla', 'macbook', 'computer', 'internet', 'microsoft', 'browser'}
>>>