【问题标题】:In python, how do I make a collection that is sorted by one value, and indexable by another在 python 中,如何创建一个按一个值排序并可由另一个值索引的集合
【发布时间】:2015-05-16 16:56:01
【问题描述】:

我需要一个集合,在其中插入诸如 [1,'b42b00d6-76c8-4d68-b22e-ff4653bb01c8'] 之类的项目。

它需要按第一个元素排序,但可以按第二个元素索引。

以下是我能想到的最好的。它有两个缺陷:

  • 它不能使用同一个键获取多个项目,因为它是 字典。
  • 无法从列表中正确删除项目。

我的尝试:

from rbtree import rbtree

class Item(object):
    def __init__(self, value, id):
         self.value = value
         self.id = id

item1 = Item(1,'b42b00d6-76c8-4d68-b22e-ff4653bb01c8')
item2 = Item(2,'60eda62f-f05d-4134-9e92-9bb9a1f52daf')
item3 = Item(2,'77d9a028-bd4b-4634-b230-234f88ff010a')
item4 = Item(3,'7e7118cd-7145-41c8-8413-79670bdc81dc')

myList = rbtree()
myList[item2.value] = item2
myList[item1.value] = item1
myList[item3.value] = item3
myList[item4.value] = item4

# Correctly ordered by the first element
# But it's missing item2.

for k,v in myList.iteritems():
    print "%s %s" % (v.value, v.id)

# But I also need to index by the second element.
# So:

listIndexedBySecondElement = {}
listIndexedBySecondElement[item1.id] = item1
listIndexedBySecondElement[item2.id] = item2
listIndexedBySecondElement[item3.id] = item3
listIndexedBySecondElement[item4.id] = item4

item = listIndexedBySecondElement['7e7118cd-7145-41c8-8413-79670bdc81dc']
print item.value # correctly prints 3

# Now I need to delete an element.

del listIndexedBySecondElement['b42b00d6-76c8-4d68-b22e-ff4653bb01c8']
# But I also need to delete it from myList. How do I do that?

【问题讨论】:

  • 当说“订购者”时,你是什么意思?你的意思是你想让它按照那个顺序显示,还是你真的想用那个顺序什么?
  • 我需要对数据进行一些分析,这要求它是有序的。所以应该排序。每次添加或删除项目时都会进行分析。
  • 对不起,但这仍然不能回答我的问题。分析对需要排序的数据做什么?例如,它会迭代它吗?排序是否可以作为分析的一部分而不是在数据结构本身中编码?
  • 它将值相加,从最低值开始,直到总和为某个值(例如 10),然后返回该值。一般要经过至少 20 项才能达到所需的总和。
  • rbtree 模块是什么?

标签: python collections sorted indexed


【解决方案1】:

运行前:

del listIndexedBySecondElement['b42b00d6-76c8-4d68-b22e-ff4653bb01c8']

抓住物品:

itm = listIndexedBySecondElement['b42b00d6-76c8-4d68-b22e-ff4653bb01c8']

现在您可以从两者中删除它:

del listIndexedBySecondElement['b42b00d6-76c8-4d68-b22e-ff4653bb01c8']
del myList[itm.value]

至于“顺序”部分 - 字典不是有序的数据结构,因此您必须实现其他内容。

【讨论】:

    【解决方案2】:

    你可以用一个 id 字典来代替:

    mydict = {}
    mydict['77d9a028-bd4b-4634-b230-234f88ff010a'] = 2
    mydict['b42b00d6-76c8-4d68-b22e-ff4653bb01c8'] = 1
    mydict['7e7118cd-7145-41c8-8413-79670bdc81dc'] = 3
    mydict['60eda62f-f05d-4134-9e92-9bb9a1f52daf'] = 2
    

    字典现在可以通过 id 进行索引。您可以像这样按 value 排序和打印:

    sorted_dict = sorted(mydict.items(), key=lambda x:x[1])
    for id, value in sorted_dict:
        print("{0} {1}".format(id, value))
    

    印刷:

    b42b00d6-76c8-4d68-b22e-ff4653bb01c8 1
    77d9a028-bd4b-4634-b230-234f88ff010a 2
    60eda62f-f05d-4134-9e92-9bb9a1f52daf 2
    7e7118cd-7145-41c8-8413-79670bdc81dc 3
    

    按值排序。

    【讨论】:

    • 该方法的一个问题是我每次插入后都需要对其进行排序,我认为这会很慢。我还需要用同一个键存储多个条目。
    • @abtree:如果您需要使用相同的键存储多个项目,当您尝试按该键进行索引时,您希望发生什么?
    • 正如 alfasin 上面所说的,字典并不是意味着有一个明确的顺序。 @abtree
    • 为什么两个项目会有相同的ID? @BrenBarn
    • 对不起,我误会了。不会有多个带有诸如“77d9a028-bd4b-4634-b230-234f88ff010a”之类的键的条目。
    【解决方案3】:

    我的最终解决方案是结合使用 alfasin 的答案,并从 rbtree 切换到 pyavl。 Pyavl 是一个集合而不是字典,所以它可以有重复。

    代码:

    import avl
    
    class Item(object):
        def __init__(self, value, id):
            self.value = value
            self.id = id
    
    item1 = Item(1,'b42b00d6-76c8-4d68-b22e-ff4653bb01c8')
    item2 = Item(2,'60eda62f-f05d-4134-9e92-9bb9a1f52daf')
    item3 = Item(2,'77d9a028-bd4b-4634-b230-234f88ff010a')
    item4 = Item(3,'7e7118cd-7145-41c8-8413-79670bdc81dc')
    
    myList = avl.new()
    myList.insert(item2)
    myList.insert(item1)
    myList.insert(item3)
    myList.insert(item4)
    
    # Correctly ordered by the first element
    for item in myList:
        print "%s %s" % (item.value, item.id)
    
    # But I also need to index by the second element.
    # So:
    
    listIndexedBySecondElement = {}
    listIndexedBySecondElement[item1.id] = item1
    listIndexedBySecondElement[item2.id] = item2
    listIndexedBySecondElement[item3.id] = item3
    listIndexedBySecondElement[item4.id] = item4
    
    item = listIndexedBySecondElement['7e7118cd-7145-41c8-8413-79670bdc81dc']
    print item.value # correctly prints 3
    
    # Now I need to delete an element.
    
    itm = listIndexedBySecondElement['60eda62f-f05d-4134-9e92-9bb9a1f52daf']
    del listIndexedBySecondElement['60eda62f-f05d-4134-9e92-9bb9a1f52daf']
    myList.remove(itm)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-10-18
      • 1970-01-01
      • 2012-05-18
      • 2023-03-21
      • 1970-01-01
      • 1970-01-01
      • 2020-10-16
      • 1970-01-01
      相关资源
      最近更新 更多