像独立数据访问一样的元组列表

时间:2016-07-17 22:35:11

标签: python list python-2.7 data-structures

我有一些配对对象以相同的级别优先级链接在一起。它们可以分组为固定长度的元组,所有都必须在列表中。某些对象类型是唯一的,其他对象可能很常见)。 例如,在这个数据结构中,我有一个对象,一个对象名称(都是唯一的),一个对象类型和一个bool(都是常见的)。

[(Banana, myBanana, fruit, True),
(Water, myWater, liquid, True),
(Car, myCar, vehicle, False)]

然后我需要找到一种简单的方法来访问知道唯一对象的其他数据。如果我拿起香蕉"如果我选择" myCar"我会得到(myBanana,fruit,True)。我得到了(车,车,假)。我不需要通过公共值访问,他们只是在那里表明数据结构可以具有共同的值并且它们可能会发生变化。订单可能不重要,为简单起见,我使用了一个列表。

显然,我可以使用其中一个唯一对象创建2个词典,每个都作为键,但实际上我可能会有更复杂的情况,更多的唯一对象类型和一些相关数据(例如最后一个bool)可能会改变,这会强制我要改变所有其他词典。 一个想法可能是创建一个包含每种数据类型的单独列表的类,对所选的"列使用index()"并返回其他列表[index]值的元组。 有更好/更快/更好/更优雅和pythonic的方式吗?

2 个答案:

答案 0 :(得分:0)

我尝试了制作课程的解决方案。它确实有效,我相信它是相当pythonic。它使用两个dicts:一个是每个唯一是公共密钥,一个是包含密钥的dict。由于没有人给出答案,我想我也可以分享一下。

class Foo(object):  # Didn't know how to name it.

    def __init__(self):
        self.value = dict()
        self.key = dict()

    def add(self, keys, values):
        for key in keys:
            self.value[key] = values  # Each key reference the values.
            self.key[key] = keys  # Each key reference to all the keys that reference the values.

    def remove(self, key):
        keys = self.key[key]  # Get all the keys that reference the same values as key.
        for key in keys:
            del self.key[key]  # Delete all keys associated with the key.
            del self.value[key]  # Delete all values associated with the key.

    def __getitem__(self, key):
        return self.value[key]

    def __setitem__(self, key, value):
        keys = self.key[key]  # Get all the keys that reference the same values as key.
        for key in keys:
            self.value[key] = value  # Make all the keys reference the new value.

    def __repr__(self):
        output = []
        temp = []
        for key in self.key:
            if key not in temp:
                temp.extend(self.key[key])
                output.append("{}: {}".format(self.key[key], self.value[key]))
        return "{" + ", ".join(output) + "}"

我尝试了它,它确实按预期工作。

a = Foo()
a.add(["Car", "My_car"], [0, True])

print(a["Car"])  # OUTPUT: [0, True]
print(a["My_car"])  # OUTPUT: [0, True]

a["Car"][0] = -1
print(a["Car"])  # OUTPUT: [-1, True]
print(a["My_car"])  # OUTPUT: [-1, True]

a["Car"][1] = False
print(a["Car"])  # OUTPUT: [-1, False]
print(a["My_car"])  # OUTPUT: [-1, False]

a["Car"] = [100, None]
print(a["Car"])  # OUTPUT: [100, None]
print(a["My_car"])  # OUTPUT: [100, None]

a["My_car"][0] = -1
print(a["My_car"])  # OUTPUT: [-1, None]
print(a["Car"])  # OUTPUT: [-1, None]

a["My_car"][1] = False
print(a["My_car"])  # OUTPUT: [-1, False]
print(a["Car"])  # OUTPUT: [-1, False]

a["My_car"] = [100, None]
print(a["My_car"])  # OUTPUT: [100, None]
print(a["Car"])  # OUTPUT: [100, None]

print(a)  # OUTPUT: {['Car', 'My_car']: [100, None]}
a.remove("My_car")
print(a)  # OUTPUT: {}
a.add(["Car", "My_car"], [0, True])
print(a)  # OUTPUT: {['Car', 'My_car']: [0, True]}
a.remove("Car")
print(a)  # OUTPUT: {}

它适用于多个键和多个值:

a.add(["Car", "My_car"], [0, True])
a.add(["Boat", "My_boat", "Sea"], [1, False, "testing"])
a.add(["Soap", "My_soap", "Bath", "Water"], [3])

print(a["Car"])  # OUTPUT: [0, True]
print(a["My_boat"])  # OUTPUT: [1, False, 'testing']
print(a["Soap"])  # OUTPUT: [3]
print(a["Water"])  # OUTPUT: [3]

问题是,当它的大小增加时,它可能会消耗掉一些内存。

答案 1 :(得分:0)

与此同时,我提出了三种不同的解决方案。

<强> 1。常用字典

第一个是一个常用字典,它使用每个唯一字段作为键,并将完整组元组在字典中转换为值。这不需要一个类,返回公共字典的函数就足够了。这是一个测试功能:

def build_structure(data, indexes=(0, )):
    result = {}
    for elem in data:
        for index in indexes:
            result[elem[index]] = elem
    return result

使用示例列表,返回的结构如下:

{
Banana: {key1: Banana, key2: myBanana, value1: fruit, value2: True},
myBanana: {key1: Banana, key2: myBanana, value1: fruit, value2: True},
...: {..:..},
myCar: {key1: Car, key2: myCar, value1: vehicle, value2: False},
}

当数据增长时,这不会占用太多内存,因为每个值都是对完整组字典的引用,因为我可以调用structure['somekey']并直接获取结果并附加值只是简单易用structure.update(structure_func(new_data))的问题;实现也非常简单,但是有些副作用:它返回一个(显然是无序的)字典,其中也包含搜索键本身,而我更喜欢保留不带搜索键的插入顺序,如果你有两个相似的键在不同的关键字段中,结果将被覆盖。

<强> 2。具有倒轴的列表列表

第二个解决方案是使用原始给定数据中的列表列表的类,其中每个嵌入列表实际上包含每个组数据列表的字段值。测试代码:

class MyStructure(object):
    def __init__(self, data):
        self.data = [[data[i][col] for i in range(len(data))] for col in range(len(data[0]))]
    def get(self, col, data):
        index = self.data[col].index(data)
        return [self.data[c][index] for c in range(len(self.data)) if c!= col]
    def append(self, data):
        for i, v in enumerate(data):
            self.data[i].append(v)

然后,最终的结构将是这样的:

[[Banana, Water, Car],
[myBanana, myWater, myCar],
[fruit, liquid, vehicle],
[True, True, False]]

第一个解决方案(使用简单的structure.get())的唯一缺点是搜索查询首先会涉及给定字段的list.index(),然后是数据[field_id] [index ]用于其他每个搜索字段。此外,您必须知道搜索查询的字段ID。

第3。带列表参考的字典

第三个解决方案是一个类,它使用原始列表列表和一个包含每个键字段的字典的列表,该列表引用了前面提到的列表索引。结构将是这样的:

[{
  Banana: [Banana, myBanana, fruit, True],
  Water: [Water, myWater, liquid, True],
  [...]
 },
 {
  myBanana: [Banana, myBanana, fruit, True],
  [...]
}]

同样,调用搜索查询需要用户知道搜索将发生的字段:给定字段ID和搜索键,该方法将为该字典执行get并返回其他字段值的列表(减去给定的密钥)。我还可以创建一个搜索每个搜索字段并返回可能匹配列表的方法。

这是我做的测试课程:

class NewStructure(object):
    def __init__(self, data):
        self.data = data
        self.field_dicts = []
        for field in range(len(data[0])):
            self.field_dicts.append({data[index][field]:item for index, item in enumerate(data)})
    def get(self, column, value):
        return [v for i, v in enumerate(self.field_dicts[column][value]) if i!=column]
    def append(self, data):
        self.data.append(data)    
        for index, field in enumerate(self.field_dicts):    
            field[data[index]] = self.data[-1]```

这实际上是一个更复杂的解决方案,但我认为它比其他解决方案更具优势:原始数据结构不会改变,即使不同字段有相似的键;当主数据结构增长时,字典的实际增长是最小的,因为它们只包含对主数据结构索引的引用。在给定的示例中,我使用每个字段作为可能的搜索字段,向__init__添加允许的搜索字段索引可能会使用更少的内存:例如,仅指定前两个字段可以是搜索字段,只需要2个参考字典,而不是4个。

我想应该根据他/她的案例场景选择解决方案。在我的情况下,我实际上并不需要“实时”结果,我认为我坚持使用最后的解决方案,可能在类init上添加动态方法创建和要求字段名称,允许structure.get_from_key1(Banana)之类的内容。

但是。我不是程序员,我只是为了好玩而这样做;所以,如果有人有其他想法,我想知道,即使只是了解不同的观点。 :)

谢谢!

PS:另外,如果有人对这个问题有更好更清晰的标题,我很乐意编辑它。