【问题标题】:Python Dictionary index of a value值的 Python 字典索引
【发布时间】:2013-04-23 02:14:43
【问题描述】:

我目前正在尝试从字典中获取值的索引,但不确定要尝试什么。

我的字典是:

    midi2notes = {                                  
        'c':("0","12","24","36","48","60","72","84","96","108","120"),
        'des':("1","13","25","37","49","61","73","85","97","109","121"),
        'd':("2","14","26","38","50","62","74","86","98","110","122"),
        'ees':("3","15","27","39","51","63","75","87","99","111","123"),
        'e':("4","16","28","40","52","64","76","88","100","112","124"),
        'f':("5","17","29","41","53","65","77","89","101","113","125"),
        'ges':("6","18","30","42","54","66","78","90","102","114","126"),
        'g':("7","19","31","43","55","67","79","91","103","115","127"),
        'aes':("8","20","32","44","56","68","80","92","104","116"),
        'a':("9","21","33","45","57","69","81","93","105","117"),
        'bes':("10","22","34","46","58","70","82","94","106","118"),
        'b':("11","23","35","47","59","71","83","95","107","119")
    }

示例:我想从 key-'c' 获取 value-"60" 的索引。应该是 5。最有效/最快的方法是什么。

【问题讨论】:

    标签: python dictionary indexing key key-value


    【解决方案1】:

    我愿意:

    midi2notes['c'].index('60')
    

    如果未找到索引,这将引发 ValueError,但如果数字通常在元组中,则很难击败优化的 C 后端。

    >>> midi2notes = {                                  
    ...         'c':("0","12","24","36","48","60","72","84","96","108","120"),
    ...         'des':("1","13","25","37","49","61","73","85","97","109","121"),
    ...         'd':("2","14","26","38","50","62","74","86","98","110","122"),
    ...         'ees':("3","15","27","39","51","63","75","87","99","111","123"),
    ...         'e':("4","16","28","40","52","64","76","88","100","112","124"),
    ...         'f':("5","17","29","41","53","65","77","89","101","113","125"),
    ...         'ges':("6","18","30","42","54","66","78","90","102","114","126"),
    ...         'g':("7","19","31","43","55","67","79","91","103","115","127"),
    ...         'aes':("8","20","32","44","56","68","80","92","104","116"),
    ...         'a':("9","21","33","45","57","69","81","93","105","117"),
    ...         'bes':("10","22","34","46","58","70","82","94","106","118"),
    ...         'b':("11","23","35","47","59","71","83","95","107","119")
    ...     }
    >>> midi2notes['c'].index('60')
    5
    >>> midi2notes['c'].index('180')
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ValueError: tuple.index(x): x not in tuple
    >>> 
    

    【讨论】:

    • 另外,请注意,如果元组中有另一个 "60" (在这种情况下没有),这将不起作用。但是,+1 :)。
    • @Haidro:在这种情况下,没有任何代码可以工作,因为当60s 可以有多个时,“60 的索引”不是一个明确定义的东西……
    • @Haidro -- 当然,如果它不是唯一的,那么整个前提都是错误的。也就是说,从算法上讲,如果您 bisect 元组(因为它们似乎都已排序),您可以做得更好。不过,对于这种大小的元组,我怀疑它会表现得更好。 编辑二等分不起作用,因为它们没有排序,因为它们是字符串而不是整数。
    • 如果这个操作被执行了无数次(技术术语),那么创建一个像mi = {(k, v): i for k,vv in midi2notes.items() for i,v in enumerate(vv)} 这样的索引字典可能是值得的。
    • @mgilson:我猜bisect 实际上会更慢。即使它只是 O(log N) 而不是 O(N),但对于 OP 的输入数据,您正在谈论 11 个超级平凡的 C 循环与 4 个不那么平凡的循环……
    【解决方案2】:

    如果您需要经常这样做,而不是每次都查找索引,只需创建一个 dict 将值映射回索引:

    midi2notes_map = {key: {value: index for index, value in enumerate(tup)}
                      for key, tup in midi2notes.items()}
    

    那么你可以这样做:

    midi2notes_map['c']['60']
    

    或者,或者:

    midi2notes_map = {(key, value): index
                      for key, tup in midi2notes.items()
                      for index, value in enumerate(tup)}
    
    midi2notes_map['c', 60]
    

    每次进行查找时,这应该会提高 5 倍的效率(因为您只需要对键进行哈希处理,而不是线性搜索 10 个项目的元组)……但当然,构建地图需要一些时间,因此,如果您只进行几次查找,则可能不值得。

    当然,在担心它之前,您应该确保此查找的性能确实相关。 (我猜你能想到的最慢的实现,使用一个显式的嵌套循环,仍然足够快来播放一个 MIDI 序列......)如果是这样,使用timeit 和你的实际数据设置一个测试和使用模式来找出什么是真正最快的。

    【讨论】:

    • @mgilson:真的,这取决于他的应用程序的其余部分是什么样的。如果他对midi2notes_map['c'] 有别的用处,第一个肯定更好;如果没有这种可以想象的用途,可能是第二种。 (我认为hash(('c', 60)) 和一个查找会比两个更简单的哈希和查找更快……但是将整个哈希表放入缓存行也可能会有所不同……)
    • 这是一种非常有用且多样化的方法,虽然它现在比我的应用程序需要的要多一些,但如果我将来扩展它(如我计划的那样),这将是巨大的有帮助。
    【解决方案3】:

    enumerate():

    >>> for x,y in enumerate(midi2notes['c']):
    ...     if y == "60":
    ...         print x
    ... 
    5
    

    【讨论】:

    • 不错的一个。可以改成生成器。
    猜你喜欢
    • 1970-01-01
    • 2016-05-25
    • 1970-01-01
    • 1970-01-01
    • 2017-01-10
    • 2013-07-21
    • 2021-02-27
    • 1970-01-01
    • 2013-02-13
    相关资源
    最近更新 更多