【问题标题】:How to assign ordinal numbers of unique values to a list in Python?如何将唯一值的序数分配给Python中的列表?
【发布时间】:2017-09-15 18:58:27
【问题描述】:

假设我有一个列表

A = ['A', 'A', 'A', 'B', 'B', 'C']

如何把它变成

B = [0, 0, 0, 1, 1, 2]

?

我是这样写的

C = {t[1]:t[0] for t in enumerate(list(set(A)))}
B = [C[e] for e in A]

它给了

[1, 1, 1, 2, 2, 0]

即顺序是随机的,而且整个代码看起来也很复杂。

有没有更简单的方法?

【问题讨论】:

  • 套装未排序。
  • 使用sorted(set(A)),而不是list(set(A))(以任意顺序创建列表)。
  • A 中的项目在您的示例中是否任意只是大写字母?到目前为止的答案取决于这是对数据的准确表示。
  • A = ['A', 'A', 'A', 'B', 'A', 'B', 'C', 'B'] 时会发生什么?

标签: python list unique


【解决方案1】:

您希望顺序由唯一元素的字母顺序决定,还是由它们在原始列表中首次出现的顺序决定?例如,应该 ['C', 'A', 'A', 'A', 'B', 'B', 'C'] 变成 [2,0,0,0,1,1,2] , 还是 [0,1,1,1,2,2,0]?如果是前者:

uniques = list(set(A))
uniques.sort()
uniques_dict = {uniques[i]:i for i in range(len(uniques))}
B = [uniques_dict[a] for a in A]

对于后者:

uniques_dict = {}
ordinal = 0
for a in A:
  if not (a in uniques_dict.keys):
     uniques_dict[a] = ordinal
     ordinal = ordinal+1
B = [uniques_dict[a] for a in A]

【讨论】:

    【解决方案2】:

    我会假设: 1. 你不依赖元素是字母; 2. 您想根据列表中的第一次出现A 对它们进行索引。

    >>> A = ['A', 'A', 'A', 'B', 'B', 'C']
    >>> seen=set()
    >>> C={x:len(seen)-1 for x in A if not (x in seen or seen.add(x))}
    >>> C
    {'B': 1, 'C': 2, 'A': 0}
    >>> list(map(C.get, A))
    [0, 0, 0, 1, 1, 2]
    

    第二行定义了一个集合seen,它将存储我们在下一行的列表推导中已经看到的A的元素。

    第三行定义了将唯一元素映射到其索引的字典。这有点棘手(虽然不是那么不寻常)。

    我们遍历A 的值。

    • 案例 1:值 x 可见,因此 x in seen or ...True,第二部分未评估,not(...) 返回 Falsex 被忽略。

    • 案例 2:x 的值 not 可见,因此 x in seenFalse 并评估第二部分。提醒seen.add 将始终返回None,在这种情况下相当于Falsex in seen or seen.add(x)False ,但 x 已添加到 seen。而not(...) 返回Truex 映射到seen 的len,每个新元素加一。

    第六行简单地将新定义的字典映射到A的值。

    【讨论】:

      【解决方案3】:

      您可以尝试一些讨厌的(尽管比您当前的代码更容易理解),例如:

      >>> B = [ord(x) - 65 for x in A]
      >>> B
      [0, 0, 0, 1, 1, 2]
      

      如果 A 是一个大列表,请考虑让 B 成为生成器,如下所示:

      B = (ord(x) - 65 for x in A)
      

      【讨论】:

      • 字母只是例子。
      【解决方案4】:
      a = ['A', 'A', 'A', 'B', 'B', 'C']
      x = sorted(set(a))
      b = [x.index(y) for y in a]
      print(b)
      [0, 0, 0, 1, 1, 2]
      

      【讨论】:

        【解决方案5】:

        似乎构建字典/映射是关键,使用它只是主题的变体。甚至构建字典也会是一个主题的变体——更好/更差/简单/复杂是读者的心声。

        >>> import itertools
        >>> ordinatates = itertools.count(0)
        >>> a = ['a', 'b', 'c', 'a', 'a', 'c', 'c']
        >>> unique = sorted(set(a))
        >>> d = {thing:ordinal for thing, ordinal in zip(unique, ordinates)}
        

        应用它

        >>> list(map(d.get, a))
        [0, 1, 2, 0, 0, 2, 2]
        >>>
        

        如果a 中有不在d 中的项目,它将抛出 KeyException。

        类似的,同样的警告:

        >>> import operator
        >>> a = ['a','b','c', 'a', 'a', 'c','c']
        >>> m = map(operator.itemgetter, a)
        >>> [get(d) for get in m]
        [0, 1, 2, 0, 0, 2, 2]
        >>>
        

        类似

        class Foo(dict):
            def __call__(self, item):
                '''Returns self[item] or None.'''
                try:
                    return self[item]
                except KeyError as e:
                    # print or log something descriptive - print(repr(e))
                    return None
        
        >>> ordinates = itertools.count(0)
        >>> a = ['a','b','c', 'a', 'a', 'c','c']
        >>> unique = sorted(set(a))
        >>> d = Foo((thing,ordinal) for thing, ordinal in zip(unique, ordinates))
        >>> result = list(map(d, a))
        >>> result
        [0, 1, 2, 0, 0, 2, 2]
        >>>
        

        所有假设您想要排序项目的序号位置 - 因为您的示例列表很方便地进行了 排序。如果您要查找列表中第一次出现独特事物的位置,请按如下方式构建映射:

        import itertools
        ordinal = itertools.count()
        b = ['c','b','c', 'a', 'a', 'c','c']
        d = {}
        for thing in b:
            if thing in d:
                continue
            d[thing] = next(ordinal)
        

        应用

        >>> list(map(d.get, b))
        [0, 1, 0, 2, 2, 0, 0]
        >>>
        

        @Abdou 在他的评论中提到了这一点,但你没有回答。

        如果你有一个单行恋物癖可以写成

        d = {}
        d.update((thing,d[thing] if thing in d else next(ordinal)) for thing in b)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-06-22
          • 1970-01-01
          相关资源
          最近更新 更多