【问题标题】:Replacing python list elements with key用键替换python列表元素
【发布时间】:2016-06-02 22:28:57
【问题描述】:

我有一个非唯一字符串列表:

list = ["a", "b", "c", "a", "a", "d", "b"]

我想用唯一标识每个字符串的整数键替换每个元素:

list = [0, 1, 2, 0, 0, 3, 1]

数字无所谓,只要是唯一标识符即可。

到目前为止,我能想到的就是将列表复制到一个集合中,并使用集合的索引来引用该列表。不过我相信还有更好的方法。

【问题讨论】:

  • 所有的“字符串”都是单字符吗?如果是这样,您可以考虑使用ord 函数。 Sets 不支持索引。
  • 不一定,不。
  • 顺便说一句,不要使用 list 作为变量名,因为这会影响内置的 list 类型。这里不会有任何问题,但是如果您的脚本稍后尝试使用 list 类型来构造列表,它可能会导致神秘的错误。

标签: python list key


【解决方案1】:

这将保证唯一性,并且 id 从 0 开始是连续的:

id_s = {c: i for i, c in enumerate(set(list))}
li = [id_s[c] for c in list]

另一方面,您不应使用 'list' 作为变量名,因为它会影响内置类型 list

【讨论】:

    【解决方案2】:

    这是defaultdict 的单通道解决方案:

    from collections import defaultdict
    seen = defaultdict()
    seen.default_factory = lambda: len(seen)  # you could instead bind to seen.__len__
    
    In [11]: [seen[c] for c in list]
    Out[11]: [0, 1, 2, 0, 0, 3, 1]
    

    这是一种技巧,但值得一提!


    另一种方法suggested by @user2357112 in a related question/answer 是使用itertools.count 递增。这允许您仅在构造函数中执行此操作:

    from itertools import count
    seen = defaultdict(count().__next__)  # .next in python 2
    

    这可能更可取,因为 default_factory 方法不会在全局范围内查找 seen

    【讨论】:

    • 很聪明,我喜欢!我从来没有想过在default_factory 中使用这种反身能力。
    • @schwobaseggl 我这就是属性的用途(而不是私有),但我仍然希望它们是一种单一的构造方法(并且参考自我)......感觉有点脏/老派。 ://
    • itertools.count().next also works 用于 default_factory,或者您可以使用 seen = defaultdict(lambda: len(seen)),因为 seen 不需要存在即可创建 lambda。我更喜欢itertools.count().nextlambda: len(seen),因为它不需要在变异操作的中间检查字典的状态,但是任何一个版本都感觉default_factory 中发生了太多的魔法。
    • @user2357112 我不认为这太神奇了,这就是它的用途!令人讨厌的是 itertools.count api 对于 python 3 是不同的(你需要使用 __next__),但我同意 itertools.count 比 len 好得多(尽管两者都是 O(1))。
    • @user2357112 我错过了 lambda 部分......更糟糕的是它在范围内查找 seen 变量(可以通过绑定到 seen.__len__ 来避免这种情况(如果只有 len were a proper oo method )。这确实需要在函数中创建以避免这种情况。您的解决方案更好!
    【解决方案3】:
    >>> lst = ["a", "b", "c", "a", "a", "d", "b"]
    >>> nums = [ord(x) for x in lst]
    >>> print(nums)
    [97, 98, 99, 97, 97, 100, 98]
    

    【讨论】:

    • 这仅在列表中的每个项目都是单个字符时才有效,OP 已经说过(在评论中)我不是这样。
    • 这也可以通过 IMO 的一点解释来实现。
    【解决方案4】:

    如果你不挑剔,那就使用散列函数:它返回一个整数。对于相同的字符串,它返回相同的哈希:

    li = ["a", "b", "c", "a", "a", "d", "b"]
    li = map(hash, li)                # Turn list of strings into list of ints
    li = [hash(item) for item in li]  # Same as above
    

    【讨论】:

    • 这确实有效,假设动态结果是可以接受的。不错。
    • 这不起作用。不保证哈希是唯一的。
    【解决方案5】:

    函数式方法:

    l = ["a", "b", "c", "a", "a", "d", "b", "abc", "def", "abc"]
    from itertools import count
    from operator import itemgetter
    
    mapped = itemgetter(*l)(dict(zip(l, count())))
    

    你也可以使用一个简单的生成器函数:

    from itertools import count
    
    def uniq_ident(l):
        cn,d  = count(), {}
        for ele in l:
            if ele not in d:
                c = next(cn)
                d[ele] = c
                yield c
            else:
                yield d[ele]
    
    
    In [35]: l = ["a", "b", "c", "a", "a", "d", "b"]
    
    In [36]: list(uniq_ident(l))
    Out[36]: [0, 1, 2, 0, 0, 3, 1]
    

    【讨论】:

    • 试试l = ["\t\t", "c"]
    猜你喜欢
    • 1970-01-01
    • 2018-01-11
    • 1970-01-01
    • 1970-01-01
    • 2015-12-18
    • 2015-12-29
    • 2015-03-03
    • 1970-01-01
    相关资源
    最近更新 更多