如何拆分并转换为字典,交换键值

4

我有一个列表

["Germany + A", "France + A", "England + B", "Germany + A" ]

  • 我需要将其转换为字典
  • 我需要通过"+"拆分
  • 转换为字典并交换值
  • 如果值已存在则无需处理

期望的字典是 {"A":["Germany", "France"],"B":["England"] }

代码如下,我已经得到了字典作为输出,现在需要添加条件如果值已存在则无需处理

l = ["Germany + A", "France + A",  "England + B", "Germany + A"  ]
m = []
for i in l:
    m.append(i.split('+'))
for k,v in m:
    n ={k:v}
    print({v: k for k, v in n.items()} 
6个回答

3

我认为在这里选择易读的解决方案是最好的。

遍历列表l,然后在' + '上进行拆分。

然后,在首次遇到它们时将国家名称添加到相应的键中。

请注意使用collections.defaultdict将字典初始化为列表字典。

import collections

l = ["Germany + A", "France + A", "England + B", "Germany + A"]

d = collections.defaultdict(list)

for i in l:
    k, v = i.split(' + ')
    if k not in d[v]:
        d[v].append(k)

print(dict(d))

这将输出结果:
{'A': ['Germany', 'France'], 'B': ['England']}

如果你想坚持原来的方法,你可以再次使用 '+' 进行拆分,并使用列表推导式将结果放入列表中:
m = [i.split(' + ') for i in l]

然后,您可以像这样循环遍历m
for k, v in m:
    if k not in d[v]:
        d[v].append(k)

如果你需要中间的m列表,那么这将非常有用。


2
你应该使用set来初始化defaultdict,而不是使用list,然后使用d[v].add代替d[v].append。如果k不存在,则可以删除检查。 - TheEagle
1
使用defaultdict是正确的工具,这点值得+1。我不知道其他答案为什么要手动使用.setdefault。 - Chase
1
@程序员 在这里,“应该”是有问题的。不清楚这是否合适。我曾考虑使用一个set,并且正要这么做,但那样它将成为一个集合字典而不是列表字典,所以我还是坚持使用了列表。无论哪种方式都可以(这是一个简单的更改)。 - costaparas
是的,除非楼主要处理数百万个字符串,否则这没有任何区别。 - TheEagle

2
my_list = ["Germany + A", "France + A",  "England + B", "Germany + A"  ]
result = {}
for item in my_list:
    country, key = item.split(' + ')
    if country not in result.setdefault(key, []):
        result[key].append(country)
print(result)

作为一个附注 - 使用有意义的名称,而不是神秘的单字符名称。
作为使用dict.setdefault()的替代方案,可以使用默认值为list的collections.defaultdict或者如果顺序不重要,则可以使用set。
编辑:使用dict.setdefault和collections.defaultdict(list)之间的比较。
from collections import defaultdict
from timeit import timeit

my_list = ["Germany + A", "France + A",  "England + B", "Germany + A"  ]

def test1(my_list):
  result = {}
  for item in my_list:
      country, key = item.split(' + ')
      if country not in result.setdefault(key, []):
          result[key].append(country)
  return result

def test2(my_list):
  result = defaultdict(list)
  for item in my_list:
      country, key = item.split(' + ')
      if country not in result[key]:
          result[key].append(country)
  return result

print(timeit('test1(my_list)', setup='from __main__ import test1, my_list', number=100000))
print(timeit('test2(my_list)', setup='from __main__ import test2, my_list', number=100000))

输出

0.2819225169987476
0.3298255940026138

至少在小样本数据中,setdefault略微更快。


1

另一种实现方式

有一个很棒的Python库叫做pandas,它也可以完成一些不错的工作,并为您提供灵活性以进行操作:

# Input
L = ["Germany + A", "France + A",  "England + B", "Germany + A"  ]

# Preprocessing
L = [l.split(' + ') for l in L]

import pandas as pd
df = pd.DataFrame(L, columns=['country','type']) # give the columns some names

查看df中的内容:

>>> df
   country type
0  Germany    A
1   France    A
2  England    B
3  Germany    A

# Then, drop duplicate records:
df.drop_duplicates(['country', 'type'], inplace=True)

# Group by type, convert to list for each record and dump to a dict in one shot
grouped = df.groupby('type').apply(lambda x: x['country'].tolist()).to_dict()

而结果是:

>>> grouped
{'A': ['Germany', 'France'], 'B': ['England']}

那就这样吧。

1
这并不是最有效的解决方案,但有多种解决方案可以应对多个问题。
from itertools import groupby

s=["Germany + A", "France + A",  "England + B", "Germany + A"  ]

m=[i.strip(' ').split('+') for i in s]
[['Germany ', ' A'], ['France ', ' A'], ['England ', ' B'], ['Germany ', ' A']]

#Grouping based on alphabets 'A' , B
new=[list(g) for k, g in groupby(sorted(m,reverse=True), lambda x:x[1])]
[[['Germany ', ' A'], ['Germany ', ' A'], ['France ', ' A']],
[['England ', ' B']]]


#swapping alphabet and Countries position
new=[item[::-1] for sublist in new for item in sublist ]
[[' A', 'Germany '], [' A', 'Germany '], [' A', 'France '], [' B', 'England       ']]


dct = dict((key, tuple(v for (k, v) in pairs)) 
           for (key, pairs) in itertools.groupby(new, lambda pair: pair[0]))
{' A': ('Germany ', 'Germany ', 'France '), ' B': ('England ',)}


{k:list(set(v)) for k,v in dct.items()}

0
l = ["Germany + A", "France + A",  "England + B", "Germany + A", "Nigeria" ]
m = {}

for s in l:
    try:
        country = country.strip()
        category = category.strip()

        foo = m.setdefault(category, [])
        
        if country not in foo:
            foo.append(country)
    except ValueError as e:
        pass


print(m)

@程序员 这回答了问题。我不明白为什么要点踩。 - midrare
点赞,你可以检查上面的情况吗? - user14257643
我们正在将值附加到 foo = m.setdefault(category, []),为什么会自动更改 m - user14257643
1
@sim 这是 Python 的一个“坑”。你期望 foom[category] 是两个不同的列表,对吧?但实际上,foo 实际上是指向 m[category] 的指针。 - midrare
最后一件事,你的答案是 {'A': ['Germany', 'France'], 'B': ['England'], None: ['Nigeria']} 但我想要的是 {'A': ['Germany', 'France'], 'B': ['England']} 因为 Nigeria 没有 +,所以我们不添加该特定键。 - user14257643
显示剩余3条评论

0
l = ["Germany + A", "France + A",  "England + B", "Germany + A"  ]
m = []
dicct = {}
for i in l:
    m.append(i.split('+'))
for k,v in m:
    if v in dicct:
        if k not in dicct[v]:
            dicct[v].append(k)
    else:
        dicct[v] = []
        dicct[v].append(k)

print(dicct)

你能再检查一个场景吗?l = ["Germany + A", "France + A", "England + B", "Germany + A", "Nigeria"],在这种情况下输出结果相同,因为“Nigeria”后面没有“+”。 - user14257643
点赞,你能检查一下上面的情况吗? - user14257643

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接