【问题标题】:merging two dictionaries of lists with the same keys in python在python中合并两个具有相同键的列表字典
【发布时间】:2014-10-14 23:11:07
【问题描述】:

我的问题:

我正在尝试将两个列表字典合并到一个新字典中,交替为每个键创建 2 个原始列表的元素以创建该键的新列表。

例如,如果我有两个字典:

strings = {'S1' : ["string0", "string1", "string2"], 'S2' : ["string0", "string1"]}

Ns = {'S1' : ["N0", "N1"], 'S2' : ["N0"]}

我想合并这两个字典,这样最终的字典看起来像:

strings_and_Ns = {'S1': ["string0", "N0", "string1", "N1", "string2"], 'S2': ["string0", "N0", "string1"]}

或者更好的是,将列表中的字符串为每个键连接在一起,例如:

strings_and_Ns = {'S1': ["string0N0string1N1string2"], 'S2': ["string0N0string1"]}

(我正在尝试将 DNA 序列片段连接在一起。)

到目前为止我所做的尝试:

压缩

 for S in Ns:   
     newsequence = [zip(strings[S], Ns[S])]
     newsequence_joined = ''.join(str(newsequence))
     strings_and_Ns[species] = newsequence_joined

这并没有将序列连接成一个字符串,并且字符串的顺序仍然不正确。

使用默认字典

from collections import defaultdict
strings_and_Ns = defaultdict(list)

    for S in (strings, Ns):
        for key, value in S.iteritems():
        strings_and_Ns[key].append(value)

这里的字符串顺序也不正确...

以某种方式沿着每个键的列表移动...

for S in strings: 
    list = strings[S]
    L = len(list)
    for i in range(L):
        strings_and_Ns[S] = strings_and_Ns[S] + strings[S][i] + strings[S][i]

【问题讨论】:

  • 如果列表的长度不同,您希望如何交织列表?我能想到的方法不止一种。
  • 新列表应始终以字符串开头并以字符串结尾。 len(Ns) 始终为 len(strings)-1。

标签: python list dictionary


【解决方案1】:
strings_and_Ns = {}
for k,v in strings.items():
    pairs = zip(v, Ns[k] + ['']) # add empty to avoid need for zip_longest()
    flat = (item for sub in pairs for item in sub)
    strings_and_Ns[k] = ''.join(flat)

flat 是根据此处接受的答案构建的:Making a flat list out of list of lists in Python

【讨论】:

    【解决方案2】:

    您可以使用itertools 或使用here 声明的列表切片来实现。使用 itertools 的结果看起来非常智能。

    strings_and_Ns = {}
    for skey, sval in strings.iteritems():
        iters = [iter(sval), iter(Ns[skey])]
        strings_and_Ns[skey] = ["".join(it.next() for it in itertools.cycle(iters))]
    

    您必须注意列表的相应长度。如果一个迭代器引发StopIteration,则该键的合并结束。

    【讨论】:

    • cycle() 的这种用法很巧妙。也许有点太聪明了。 :)
    【解决方案3】:

    替换x,y 迭代插入default 缺失值:

    from itertools import izip_longest
    
    def alternate(x, y, default):
        return (item for pair in izip_longest(x, y, default) for item in pair)
    

    Example

    a = {'S1' : ["string0", "string1", "string2"], 'S2' : ["string0", "string1"]}
    b = {'S1' : ["N0", "N1"], 'S2' : ["N0"]}
    assert a.keys() == b.keys()
    merged = {k: ''.join(alternate(a[k], b[k], '')) for k in a}
    print(merged)
    

    输出

    {'S2': 'string0N0string1', 'S1': 'string0N0string1N1string2'}
    

    【讨论】:

      【解决方案4】:

      itertools.izip_longest 会处理不均匀长度的列表,然后只需使用str.join 加入一个字符串。

      strings = {'S1' : ["string0", "string1", "string2"], 'S2' : ["string0", "string1"]}
      
      Ns = {'S1' : ["N0", "N1"], 'S2' : ["N0"]}
      
      from itertools import izip_longest as iz
      
      strings_and_Ns = {k:["".join([a+b for a, b in iz(strings[k],v,fillvalue="")])] for k,v in Ns.items()}
      
      print(strings_and_Ns)
      {'S2': ['string0N0string1'], 'S1': ['string0N0string1N1string2']}
      

      等同于:

      strings_and_Ns  = {}
      for k, v in Ns.items():
           strings_and_Ns[k] = ["".join([a + b for a, b in iz(strings[k], v, fillvalue="")])]
      

      使用izip_longest 意味着无论哪个dict的值包含更多元素,代码都可以工作。

      【讨论】:

      • 好吧,你一直在编辑。我很困惑。我认为这个版本更快,但可读性较差。
      【解决方案5】:

      与发布的其他解决方案类似,但我会将其中一些移到函数中

      import itertools   
      
      def alternate(*iters, **kwargs):
          return itertools.chain(*itertools.izip_longest(*iters, **kwargs))
      
      result = {k: ''.join(alternate(strings[k], Ns[k] + [''])) for k in Ns}
      print result
      

      给予:

      {'S2': 'string0N0string1', 'S1': 'string0N0string1N1string2'}
      

      alternate 函数来自https://stackoverflow.com/a/2017923/66349。它将可迭代对象作为参数,并将每个项目连续链接在一起(使用izip_longest 作为 Padraic Cunningham 做到了)。

      您可以指定fillvalue='' 来处理不同长度的列表,或者像我上面所做的那样手动填充较短的列表(假设Ns 总是比strings 短一个)。

      如果你有一个不支持字典理解的旧版 python,你可以使用它来代替

      result = dict((k, ''.join(alternate(strings[k], Ns[k] + ['']))) for k in Ns)
      

      【讨论】:

      • 你可以使用chain.from_iterable()。
      猜你喜欢
      • 2021-11-26
      • 1970-01-01
      • 2017-04-20
      • 1970-01-01
      • 2019-11-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多