【问题标题】:List of tuple like independent data access像独立数据访问一样的元组列表
【发布时间】:2016-07-17 22:35:10
【问题描述】:

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

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

然后我需要找到一种简单的方法来访问知道唯一对象的其他数据。如果我选择“Banana”,我会得到(myBanana,fruit,True),如果我选择“myCar”,我会得到(Car,vehicle,False)。我不需要通过公共值访问,它们只是为了表明数据结构可以具有公共值并且它们可能会改变。顺序可能并不重要,为了简单起见,我使用了一个列表。

显然,我可以使用其中一个唯一对象作为键创建 2 个字典,但实际上我可能会遇到更复杂的情况,其中包含更多唯一对象类型,并且一些相关数据(例如最后一个布尔值)可能会发生变化,这将迫使我要更改所有其他字典。 一个想法可以是创建一个包含每种数据类型的单独列表的类,对选定的“列”使用 index() 并返回其他 list[index] 值的元组。 有没有更好/更快/更好/更优雅和 Pythonic 的方式来做到这一点?

【问题讨论】:

  • 也许使用命名元组? docs.python.org/3/library/…
  • 这些对我来说就像教科书类。
  • @TedKleinBergman 我不能使用命名元组,因为它们是不可变的:正如我所写,我可能不得不更改“通用”值(例如最后一个布尔值)
  • @msvalkon:你是什么意思?

标签: python list python-2.7 data-structures


【解决方案1】:

我在上课时尝试了解决方案。它确实有效,我相信它相当pythonic。它使用两个字典:一个是每个唯一的字典,一个是公共的键,另一个是包含键的字典。由于没有人给出答案,我想我不妨分享一下。

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]

问题是当它变大时可能会占用一些内存。

【讨论】:

  • 这很有趣,特别是关于使用多个可编辑值,但它不显示剩余的键(这是我需要的)。我提出了两种可能的解决方案,与此同时,我会将它们作为可能的答案发布。
【解决方案2】:

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

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

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

3.带有列表参考的字典

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

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

再次,调用搜索查询要求用户知道搜索将发生的字段:给定字段 id 和搜索键,该方法将为该 dict 执行 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]```

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

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

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

谢谢!

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

【讨论】:

    猜你喜欢
    • 2011-08-18
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    • 2023-03-30
    • 1970-01-01
    • 2013-01-02
    • 1970-01-01
    • 2021-10-30
    相关资源
    最近更新 更多