【问题标题】:Combine list elements by suffix按后缀组合列表元素
【发布时间】:2017-10-19 20:36:12
【问题描述】:

给定两个带后缀的列表:

l1 = ['C_1', 'B_1', 'A']
l2 = ['B_2', 'C_2', 'D']

我想这样组合它们:

['C_1', 'C_2', 'B_1', 'B_2', 'A', 'D']

元素将与l1 作为锚点组合。这意味着,如果C_*l1 中出现在B_* 之前,输出中将保留相同的顺序。此外,具有相同前缀C_* 的元素将按后缀升序排列在一起。带后缀的元素按照它们出现的顺序放置,如上所示。

您可以假设l1 中的所有元素都有后缀_1,而l2 中的所有元素都有后缀_2

我试过这个:

from collections import OrderedDict
from itertools import chain

o = OrderedDict()
for x in l1 + l2:
    o.setdefault(x.split('_')[0], []).append(x) 

result = list(chain.from_iterable(o.values()))

哪个有效,但想知道是否有更简洁的方法。

编辑:

后缀只是该元素出现在哪个列表中的一个代表。假设我有来自l1C_1 和来自l2C_2,然后C_* 元素根据哪个在@ 中出现987654338@ 并且在 l2 中,在最终列表中(所以,它应该是 ... C_1, C_2...)。

此外,l1l2 中的所有元素都是独一无二的。希望对您有所帮助。

【问题讨论】:

  • l2 的顺序重要吗?不在您的示例数据中,因为只有一个元素没有来自 l1 的后缀/组
  • @Jean-FrançoisFabre l1 订购是这里的锚。 l2 元素在最终列表中的顺序无关紧要。
  • 你的意思是numerical后缀,还是lexicographical后缀?
  • @WillemVanOnsem 真的,后缀只是代表该元素出现在哪个列表中。假设我有来自 l1 的 C_1 和来自 l2 的 C_2,然后 C_ 元素基于 l1 中的哪个出现并且在 l2 中,在最终列表中(所以,它会是 ... C_1,C_2 ...)。我希望这能解决问题!
  • 你也可以假设后缀总是数字,如果有帮助的话。

标签: python list


【解决方案1】:

Alex answer 很短,但使用具有O(n) 复杂性的list.index

我建议将p 构建为字典,反转迭代以模拟index 的工作方式(否则,当出现超过1 次时返回最后一个索引)。

在这种情况下,排序键函数使用 dict 查找,速度更快:

l1 = ['C_1', 'B_1', 'A']
l2 = ['B_2', 'C_2', 'D']

p = {s[0]:i for i,s in reversed(list(enumerate(l1 + l2)))}
print(sorted(l1 + l2, key=lambda x: (p[x[0]], x)))

【讨论】:

    【解决方案2】:

    使用itertools.groupby()sorted() 函数:

    import itertools
    
    l1 = ['C_1', 'B_1', 'A']
    l2 = ['B_2', 'C_2', 'D']
    l1_len = len(l1)
    groups_gen = (list(g) for k,g in itertools.groupby(sorted(l1+l2), key=lambda x: x[0] or '_' not in x))
    result = list(itertools.chain.from_iterable(sorted(groups_gen,
                  key=lambda x: l1.index(x[0]) if x[0] in l1 else l1_len)))
    
    print(result)
    

    输出:

    ['C_1', 'C_2', 'B_1', 'B_2', 'A', 'D']
    

    【讨论】:

    • 哇,这似乎比有序 dict 解决方案更复杂:p
    • Martjin 在我的一个类似答案(现已删除)上评论了该方法:使用带有排序列表的 itertools.groupby 是O(n*2 * log(n))。简洁,但可能更慢
    • 是的,先生们,我意识到这可能比使用一些 Mapping 对象的潜在解决方案要慢。但这就是我可以实现所需聚合/分组的方式。欢迎使用其他性能更好的替代解决方案
    【解决方案3】:

    按照l1中出现前缀的索引对所有元素进行排序,使用字符串的其余部分来打破平局:

    p = [s[0] for s in l1 + l2]
    print(sorted(l1 + l2, key=lambda x: (p.index(x[0]), x)))
    

    p 使用来自l1l2 的前缀,这样p.index(x[0]) 就不会引发错误。

    【讨论】:

    • 这似乎是一个非常好的选择。谢谢。
    • 它不会对剩余的项目进行排序。例如,l1 = ['c_1','b_1','a'] l2 = ['b_2','c_2','f','d']将导致['c_1','c_2','' b_1','b_2','a','f','d'],但不确定是否对您来说是可取的。
    【解决方案4】:

    这个方法就可以了

    l1 = ['C_1', 'B_1', 'A']
    l2 = ['B_2', 'C_2', 'D']
    

    首先选择所有第一个常用词项

    new=[y for item in l1 for item2 in l2 for y in  [item] + [item2] if item[0]==item2[0]]
    

    请注意,我在上面的列表理解中使用了扩展。

    现在只需找出除了第一个字母常见项目之外还剩下的项目:

        for item1 in l2:
            for item2 in l1:
                if item1 not in new:
                    new.append(item1)
    
                elif item2 not in new:
                    new.append(item2)
    
    
    print(new)
    

    【讨论】:

      猜你喜欢
      • 2013-09-03
      • 2013-10-30
      • 1970-01-01
      • 2020-07-19
      • 2014-06-23
      • 1970-01-01
      • 1970-01-01
      • 2016-12-19
      相关资源
      最近更新 更多