如何在Python中创建一个包含重复键的字典?

mfpqipee  于 2023-02-15  发布在  Python
关注(0)|答案(9)|浏览(309)

我有一个文本文件,其中包含不同值的重复汽车注册号,如下所示:

EDF768, Bill Meyer, 2456, Vet_Parking
TY5678, Jane Miller, 8987, AgHort_Parking
GEF123, Jill Black, 3456, Creche_Parking
ABC234, Fred Greenside, 2345, AgHort_Parking
GH7682, Clara Hill, 7689, AgHort_Parking
JU9807, Jacky Blair, 7867, Vet_Parking
KLOI98, Martha Miller, 4563, Vet_Parking
ADF645, Cloe Freckle, 6789, Vet_Parking
DF7800, Jacko Frizzle, 4532, Creche_Parking
WER546, Olga Grey, 9898, Creche_Parking
HUY768, Wilbur Matty, 8912, Creche_Parking
EDF768, Jenny Meyer, 9987, Vet_Parking
TY5678, Jo King, 8987, AgHort_Parking
JU9807, Mike Green, 3212, Vet_Parking

我想从这些数据创建一个字典,它使用注册号(第一列)作为键,使用行的其余部分的数据作为值。
我写了这段代码:

data_dict = {}
data_list = []

def createDictionaryModified(filename):
    path = "C:\Users\user\Desktop"
    basename = "ParkingData_Part3.txt"
    filename = path + "//" + basename
    file = open(filename)
    contents = file.read()
    print(contents,"\n")
    data_list = [lines.split(",") for lines in contents.split("\n")]
    for line in data_list:
        regNumber = line[0]
        name = line[1]
        phoneExtn = line[2]
        carpark = line[3].strip()
        details = (name,phoneExtn,carpark)
        data_dict[regNumber] = details
    print(data_dict,"\n")
    print(data_dict.items(),"\n")
    print(data_dict.values())

问题是数据文件包含注册号的重复值。当我试图将它们与data_dict[regNumber] = details存储在同一个字典中时,旧值被覆盖。
我如何制作一个有重复键的字典?
有时候,人们想通过把所有的条目放到一个dict中来"合并"多个现有的字典,并且对重复的键被覆盖感到惊讶或烦恼,请参阅相关问题How to merge dicts, collecting values from matching keys?来处理这个问题。

up9lanfz

up9lanfz1#

Python字典不支持重复键,一种方法是在字典中存储列表或集合。
实现这一点的一个简单方法是使用defaultdict

from collections import defaultdict

data_dict = defaultdict(list)

你要做的就是

data_dict[regNumber] = details

data_dict[regNumber].append(details)

你会得到一本列表字典。

8fsztsew

8fsztsew2#

你可以改变Python中内置类型的行为,对于你的例子来说,创建一个dict子类非常容易,它会自动地将重复的值存储在同一个键下的列表中:

class Dictlist(dict):
    def __setitem__(self, key, value):
        try:
            self[key]
        except KeyError:
            super(Dictlist, self).__setitem__(key, [])
        self[key].append(value)

输出示例:

>>> d = dictlist.Dictlist()
>>> d['test'] = 1
>>> d['test'] = 2
>>> d['test'] = 3
>>> d
{'test': [1, 2, 3]}
>>> d['other'] = 100
>>> d
{'test': [1, 2, 3], 'other': [100]}
mwg9r5ms

mwg9r5ms3#

与其使用defaultdict,或者进行成员测试或手动异常处理,不如使用setdefault方法在需要时向字典中添加新的空列表:

results = {}                              # use a normal dictionary for our output
for k, v in some_data:                    # the keys may be duplicates
    results.setdefault(k, []).append(v)   # magic happens here!

setdefault检查第一个参数是否(键)已经在字典中。如果没有找到任何内容,则将第二个参数赋给(默认值,本例中为空列表)作为键的新值。如果键确实存在,则不执行任何特殊操作(默认值为unused)。但无论哪种情况,(不管是旧的还是新的),所以我们可以无条件地在它上面调用append(知道它应该总是一个列表)。

krugob8w

krugob8w4#

你不能用一个带有重复键的字典来定义!相反,你可以使用一个键,以及一个拥有该键的元素列表作为值。
因此,您可以按照以下步骤操作:
1.查看当前元素的键(初始集合的键)是否在最终指令中。如果是,则转到步骤3
1.使用密钥更新字典
1.将新值追加到dict[key]列表
1.重复[1-3]

gk7wooem

gk7wooem5#

如果您希望仅在必要时使用列表,而在其他情况下使用值,则可以执行以下操作:

class DictList(dict):
    def __setitem__(self, key, value):
        try:
            # Assumes there is a list on the key
            self[key].append(value)
        except KeyError: # If it fails, because there is no key
            super(DictList, self).__setitem__(key, value)
        except AttributeError: # If it fails because it is not a list
            super(DictList, self).__setitem__(key, [self[key], value])

然后,您可以执行以下操作:

dl = DictList()
dl['a']  = 1
dl['b']  = 2
dl['b'] = 3

它将存储下面的{'a': 1, 'b': [2, 3]}
我倾向于在需要反向/反向字典时使用此实现,在这种情况下,我只需执行以下操作:

my_dict = {1: 'a', 2: 'b', 3: 'b'}
rev = DictList()
for k, v in my_dict.items():
    rev_med[v] = k

这将生成与上面相同的输出:{'a': 1, 'b': [2, 3]}.

    • 警告:**此实现依赖于append方法不存在(在您存储的值中)。如果您存储的值是列表,这可能会产生意外结果。例如,
dl = DictList()
dl['a']  = 1
dl['b']  = [2]
dl['b'] = 3

将产生与{'a': 1, 'b': [2, 3]}之前相同的结果,但可能会出现以下情况:{'a': 1, 'b': [[2], 3]}.

pbossiut

pbossiut6#

您可以参考以下文章:http://www.wellho.net/mouth/3934_Multiple-identical-keys-in-a-Python-dict-yes-you-can-.html
在一个dict中,如果一个键是一个对象,就没有重复的问题。
例如:

class p(object):
    def __init__(self, name):
        self.name = name
    def __repr__(self):
        return self.name
    def __str__(self):
        return self.name
d = {p('k'): 1, p('k'): 2}
1tu0hz3e

1tu0hz3e7#

字典中不能有重复的键。使用列表的字典:

for line in data_list:
  regNumber = line[0]
  name = line[1]
  phoneExtn = line[2]
  carpark = line[3].strip()
  details = (name,phoneExtn,carpark)
  if not data_dict.has_key(regNumber):
    data_dict[regNumber] = [details]
  else:
    data_dict[regNumber].append(details)
clj7thdc

clj7thdc8#

这是一个很老的问题,但也许我的解决办法能帮助一些人。
通过覆盖__hash__魔术方法,你可以保存相同的对象在dict.
示例:

from random import choices

class DictStr(str):
    """
        This class behave exacly like str class but
        can be duplicated in dict
    """
    def __new__(cls, value='', custom_id='', id_length=64):
        # If you want know why I use __new__ instead of __init__
        # SEE: https://stackoverflow.com/a/2673863/9917276
        obj = str.__new__(cls, value)
        if custom_id:
            obj.id = custom_id
        else:
            # Make a string with length of 64
            choice_str = "abcdefghijklmopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ1234567890"
            obj.id = ''.join(choices(choice_str, k=id_length))
        return obj

    def __hash__(self) -> int:
        return self.id.__hash__()

现在让我们创建一个法令:

>>> a_1 = DictStr('a')
>>> a_2 = DictStr('a')
>>> a_3 = 'a'
>>> a_1
a
>>> a_2
a
>>> a_1 == a_2 == a_3
True
>>> d = dict()
>>> d[a_1] = 'some_data'
>>> d[a_2] = 'other'
>>> print(d)
{'a': 'some_data', 'a': 'other'}
    • 注**:此解决方案可应用于任何基本数据结构,如(int、float ...)

解释:

我们可以使用几乎任何对象作为dict类中的键(或者在其他语言中通常称为HashMapHashTable),但是应该有一种方法来区分键,因为dict不知道对象。
为此,希望作为键添加到字典中的对象必须以某种方式为自己提供一个唯一的标识符编号(我将其命名为uniq_id,实际上是用哈希算法创建的一个编号)。
由于字典结构在大多数解决方案中广泛使用,大多数编程语言将对象uniq_id的生成隐藏在一个hash名字构建方法中,该方法在关键字搜索中提供字典
因此,如果你操作类的hash方法,你可以改变类的行为,使之成为字典键

xqkwcwgp

xqkwcwgp9#

字典不支持重复键,您可以改用defaultdict
下面是如何在python3x中使用defaultdict来解决问题的示例

from collections import defaultdict

sdict = defaultdict(list)
keys_bucket = list()

data_list = [lines.split(",") for lines in contents.split("\n")]
for data in data_list:
    key = data.pop(0)
    detail = data
    
    keys_bucket.append(key)
    if key in keys_bucket:
        sdict[key].append(detail)
    else:
        sdict[key] = detail

print("\n", dict(sdict))

以上代码将生成如下输出:

{'EDF768': [[' Bill Meyer', ' 2456', ' Vet_Parking'], [' Jenny Meyer', ' 9987', ' Vet_Parking']], 'TY5678': [[' Jane Miller', ' 8987', ' AgHort_Parking'], [' Jo King', ' 8987', ' AgHort_Parking']], 'GEF123': [[' Jill Black', ' 3456', ' Creche_Parking']], 'ABC234': [[' Fred Greenside', ' 2345', ' AgHort_Parking']], 'GH7682': [[' Clara Hill', ' 7689', ' AgHort_Parking']], 'JU9807': [[' Jacky Blair', ' 7867', ' Vet_Parking'], [' Mike Green', ' 3212', ' Vet_Parking']], 'KLOI98': [[' Martha Miller', ' 4563', ' Vet_Parking']], 'ADF645': [[' Cloe Freckle', ' 6789', ' Vet_Parking']], 'DF7800': [[' Jacko Frizzle', ' 4532', ' Creche_Parking']], 'WER546': [[' Olga Grey', ' 9898', ' Creche_Parking']], 'HUY768': [[' Wilbur Matty', ' 8912', ' Creche_Parking']]}

相关问题