【问题标题】:Unique IDs to multidimensional array elements in pythonpython中多维数组元素的唯一ID
【发布时间】:2012-01-18 21:50:03
【问题描述】:

我有一个多维数组,其中的元素可以完全随机。例如,

[
    [ [1, 2], [2, 1], [3, 1], [4, 2] ],
    [ [2, 1], [4, 3], [3, 4], [1, 3] ]
]

我想为每个唯一元素(如 [1,2] 中的元素,而不是其中的元素)分配一个 ID,以便稍后当这个数组更大时我可以识别它,但我不能似乎想通了。我已经在互联网上搜索了一段时间,但没有运气,所以如果有人可以推动我朝着正确的方向前进,我将非常感激。

【问题讨论】:

  • 使用[1, 2] 作为[1, 2] 的唯一ID 怎么样?
  • 看看hash。顺便说一句,列表是可变的——如果可能的话,你会想要使用元组。
  • @JoshBleecherSnyder:哈希可能会发生冲突,因此它们作为 ID 没有那么有用。
  • @SvenMarnach 他们可以碰撞,这是真的,但他们非常不太可能。如果他们这样做了,其他事情就会出现灾难性的错误——例如,字典查找会意外失败。考虑到它们在语言级别上的使用量,我会在任何非加密环境中使用它们。
  • @JoshBleecherSnyder:字典查找不会因为散列冲突而出错。比较哈希后,字典检查键是否真的相同,如果不是,则使用一些冲突解决策略。字典中的哈希冲突实际上很常见。

标签: python multidimensional-array unique-id


【解决方案1】:

使用这样的东西怎么样?

class ItemUniqifier(object):
    def __init__(self):
        self.id = 0
        self.element_map = {}
        self.reverse_map = {}

    def getIdFor(self, obj):
        obj_id = self.element_map.get(obj)
        if obj_id is None:
            obj_id = self.id
            self.element_map[obj] = obj_id
            self.reverse_map[obj_id] = obj
            self.id += 1
        return obj_id

    def getObj(self, id):
        return self.reverse_map.get(id)

uniqifier = ItemUniqifier()
print uniqifier.getIdFor((1,2))
print uniqifier.getIdFor((1,2))
print uniqifier.getIdFor("hello")
print uniqifier.getObj(0)
print uniqifier.getObj(1)

打印出来:

0
0
1
(1, 2)
hello

因此,例如,要创建一个大数组,您可以执行以下操作:

uniqifier = ItemUniqifier()
sample_array = []
for j in range(3):
    inside_array = []
    for i in range(10):
        inside_array.append(uniqifier.getIdFor((i, i+1)))
    sample_array.append(inside_array)

import pprint
pprint.pprint(sample_array)

for inside in sample_array:
    for elem in inside:
        print uniqifier.getObj(elem),
    print

打印出来:

[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]]
(0, 1) (1, 2) (2, 3) (3, 4) (4, 5) (5, 6) (6, 7) (7, 8) (8, 9) (9, 10)
(0, 1) (1, 2) (2, 3) (3, 4) (4, 5) (5, 6) (6, 7) (7, 8) (8, 9) (9, 10)
(0, 1) (1, 2) (2, 3) (3, 4) (4, 5) (5, 6) (6, 7) (7, 8) (8, 9) (9, 10)

【讨论】:

  • 这非常彻底。希望 OP 回来,不要 tl;博士这篇文章。
【解决方案2】:

最简单的方法是使用字典,如下所示:

id_map = { 'some_id'  : example_array[0][0][0], # maps 'some_id'  to [1, 2]
           'other_id' : example_array[0][1][3], # maps 'other_id' to [3, 4]
           # add more if wanted...
         }

虽然字典CAN同时使用字母和数字键,但不建议使用数字键来引用索引,因为这可能会导致与列表索引编号混淆。

此外,字典可以按需添加新键,如下所示:

id_map[new_key] = new_pair

既然你说列表是动态生成的,这是最好的选择。

由于每个数字对都是通过 3 个索引调用访问的,也许您应该将 id 设置为 3 位长?例如,[1, 2] 将映射到 id '000'[3, 4] 到 id '013'

Dictionaries - Python Documentation

【讨论】:

  • 刚刚意识到如果索引超过 10,建议的 id 方案将不起作用。也许用_ 将索引分开,例如0_12_2
  • 为什么要在字符串中编码一些作为列表更有用的东西? "0_12_2"[0, 12, 2] 的优势在哪里?
  • @SvenMarnach 我不明白你在问什么 - AFAIK,字典默认将键存储为字符串,即使它们最初是作为数字和布尔值传入的。另外,0_12_2 是对example_list[0][12][2] 的任何内容的引用。
  • 不,Python 中的字典不会将键转换为其他任何内容。他们只是使用你给他们的对象。而且我真的不明白“另外,0_12_2 是对example_list[0][12][2] 的任何内容的引用”这句话是什么意思。方法。 [0, 12, 2] 也可以作为对 example_list[0][12][2] 的引用——它更容易使用。
  • @SvenMarnach 如果你知道这么多,那你为什么不回答这个问题而不是不具建设性呢?仅供参考,当我使用布尔值时,调用.keys() 返回['True', 'False']
【解决方案3】:

如果每个“元素”是两个以 10 为基数的单位数的序列,您可以从其内容中为每个整数生成一个唯一的 id,如下所示:

def uniqueID(elem):
    return elem[0]*10 + elem[1]

基本思想是找出某种方法来使用元素的内容来生成 ID。当然,具体如何完成将取决于内容是什么。

【讨论】:

    【解决方案4】:

    这是另一个可以处理可变长度(甚至零长度)序列的混合类型(即列表、元组和字符串)的答案。

    class EOS(object): pass  # end-of-sequence marker
    EOS = EOS()  # singleton instance
    
    class SeqID(object):
        """ Create or find a unique ID number for a given sequence. """
    
        class TreeNode(dict):
            """ Branch or leaf node of tree """
            def __missing__(self, key):
                ret = self[key] = self.__class__()
                return ret
    
        def __init__(self, first_ID=1):
            self._next_ID = first_ID
            self._root = self.__class__.TreeNode()
    
        def __getitem__(self, seq):
            # search tree for a leaf node corresponding
            # to given sequence and creates one if not found
            node = self._root
            for term in seq:
                node = node[term]
            if EOS not in node:  # first time seq encountered?
                node[EOS] = self._next_ID
                self._next_ID += 1
            return node[EOS]
    
    
    elements = [
        [ [1, 2], [1, 3], [2, 1], [3, 1], [4, 2] ],
        [ [], [2, 1], [4, 3], [3, 4], (1, 3) ],
        [ [2, 2], [9, 5, 7], [1, 2], [2, 1, 6] ],
        [ 'ABC', [2, 1], [3, 4], [2, 3], [9, 5, 7] ]
    ]
    
    IDs = SeqID(1000)
    print '['
    for row in elements:
        print '  [ ',
        for seq in row:
            print '%r: %s,' % (seq, IDs[seq]),
        print ' ],'
    print ']'
    

    使用测试用例中显示的多维数组的元素,这些元素与您的示例类似,但有几个添加,产生以下输出。请注意,生成的 ID 号已强制以 1000 开头,以便更容易在输出中发现。

    [
      [  [1, 2]: 1000, [1, 3]: 1001, [2, 1]: 1002, [3, 1]: 1003, [4, 2]: 1004,  ],
      [  []: 1005, [2, 1]: 1002, [4, 3]: 1006, [3, 4]: 1007, [1, 3]: 1001,  ],
      [  [2, 2]: 1008, [9, 5, 7]: 1009, [1, 2]: 1000, [2, 1, 6]: 1010,  ],
      [  'ABC': 1011, [2, 1]: 1002, [3, 4]: 1007, [2, 3]: 1012, [9, 5, 7]: 1009,  ],
    ]
    

    代码的工作原理是根据每个序列中的元素出现的顺序以及它们是什么,在内部构造一个多分支的搜索树。

    一个潜在的警告是,生成的 ID 取决于第一次看到每个唯一序列的顺序,因为每个新 ID 只是比最后一个多一个。

    还要注意,保存在不同容器中的相同元素的序列将生成相同的 ID,因为在显示的代码中忽略了序列的类型 - 但也可以更改它以考虑类型。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-15
      • 2021-03-15
      • 2023-04-06
      • 1970-01-01
      • 2016-06-02
      • 1970-01-01
      相关资源
      最近更新 更多