82

我有以下列表,其中包含具有不同值的重复汽车登记号。我想把它转换成一个接受这多个汽车登记号码键的字典。

到目前为止,当我尝试将列表转换为字典时,它消除了其中一个键。如何制作带有重复键的字典?

名单是:

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()
4

9 回答 9

139

Python 字典不支持重复键。一种解决方法是将列表或集合存储在字典中。

实现此目的的一种简单方法是使用defaultdict

from collections import defaultdict

data_dict = defaultdict(list)

你所要做的就是更换

data_dict[regNumber] = details

data_dict[regNumber].append(details)

你会得到一个列表字典。

于 2012-05-19T11:41:15.263 回答
48

您可以更改 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]}
于 2012-05-19T12:42:38.843 回答
9

你不能有一个带有重复键的字典来定义!相反,您可以使用单个键,并将具有该键的元素列表作为值。

因此,您可以按照以下步骤操作:

  1. 查看当前元素的(您的初始集合中的)键是否在最终字典中。如果是,请转到步骤 3
  2. 用键更新字典
  3. 将新值附加到 dict[key] 列表
  4. 重复 [1-3]
于 2012-05-19T11:40:59.913 回答
8

可以参考以下文章: 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}
于 2018-09-06T13:24:55.780 回答
8

我刚刚发布了一个问题的答案,该问题随后作为该问题的副本关闭(我认为有充分的理由),但我很惊讶地看到我提出的解决方案未包含在此处的任何答案中。

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,它会检查第一个参数(键)是否已经在字典中。如果没有找到任何东西,它会将第二个参数(默认值,在这种情况下为空列表)分配为键的新值。如果密钥确实存在,则不做任何特殊处理(默认未使用)。但是,无论哪种情况,值(无论是旧的还是新的)都会返回,因此我们可以无条件地调用append它,知道它应该始终是一个列表。

于 2019-05-01T17:37:40.697 回答
6

如果您只想在必要时拥有列表,而在任何其他情况下才拥有值,那么您可以这样做:

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]}.


CAVEAT:此实现依赖于append方法的不存在(在您存储的值中)。如果您存储的值是列表,这可能会产生意想不到的结果。例如,

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

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

于 2018-01-30T09:26:03.413 回答
3

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

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)
于 2012-05-19T11:50:22.793 回答
0

字典不支持重复键,你可以使用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']]}
于 2021-04-16T08:24:12.700 回答
0

这是一个古老的问题,但也许我的解决方案可以帮助某人。

通过覆盖__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名称构建方法中,该方法在键搜索中提供 dict

因此,如果您操作hash类的方法,则可以将类的行为更改为字典键

于 2021-09-15T21:09:16.150 回答