【问题标题】:Repeating letters like excel columns?重复像excel列这样的字母?
【发布时间】:2017-02-12 00:01:55
【问题描述】:

我想创建一个类似于 Microsoft Excel 中的列字母的字符串列表。例如,26列之后,接下来的列变为AAABAC等。

我尝试过使用取模运算符,但最终得到的是AABBCC 等...

import string

passes_through_alphabet = 0

for num, col in enumerate([_ for _ in range(40)]):
    if num % 26 == 0:
        passes_through_alphabet += 1
    excel_col = string.ascii_uppercase[num%26] * passes_through_alphabet
    print(num, excel_col)

0 A
1 B
2 C
3 D
...
22 W
23 X
24 Y
25 Z
26 AA
27 BB
28 CC
...

【问题讨论】:

    标签: python excel string modulus


    【解决方案1】:

    您可以为此使用itertools.product

    >>> import itertools
    >>> list(itertools.product(string.ascii_uppercase, repeat=2))
    [('A', 'A'), ('A', 'B'), ('A', 'C'), ('A', 'D'), ...
    

    将其与第一组字母组合,然后将它们连接起来:

    >>> list(
    ...     itertools.chain(
    ...         string.ascii_uppercase, 
    ...        (''.join(pair) for pair in itertools.product(string.ascii_uppercase, repeat=2))
    ... ))
    ['A', 'B', 'C', .. 'AA', 'AB', 'AC' .. 'ZZ']
    

    概括地说,我们定义了一个生成越来越大的产品的生成器。请注意,yield from 仅在 python 3.3+ 中可用,但如果您使用的是 python 2,则可以使用 for 循环来生成每个项目。

     >>> def excel_cols():
    ...:     n = 1
    ...:     while True:
    ...:         yield from (''.join(group) for group in itertools.product(string.ascii_uppercase, repeat=n))
    ...:         n += 1
    
    >>> list(itertools.islice(excel_cols(), 28))
    ['A',
     'B',
     'C',
     ...
     'X',
     'Y',
     'Z',
     'AA',
     'AB']
    

    【讨论】:

      【解决方案2】:

      基于这个答案:https://stackoverflow.com/a/182009/6591347

      def num_to_excel_col(n):
          if n < 1:
              raise ValueError("Number must be positive")
          result = ""
          while True:
              if n > 26:
                  n, r = divmod(n - 1, 26)
                  result = chr(r + ord('A')) + result
              else:
                  return chr(n + ord('A') - 1) + result
      

      【讨论】:

        【解决方案3】:

        这个生成器函数可以处理任意字母:

        import string
        
        def labels(alphabet=string.ascii_uppercase):
            assert len(alphabet) == len(set(alphabet))  # make sure every letter is unique
            s = [alphabet[0]]
            while 1:
                yield ''.join(s)
                l = len(s)
                for i in range(l-1, -1, -1):
                    if s[i] != alphabet[-1]:
                        s[i] = alphabet[alphabet.index(s[i])+1]
                        s[i+1:] = [alphabet[0]] * (l-i-1)
                        break
                else:
                    s = [alphabet[0]] * (l+1)
        
        > x = labels(alphabet='ABC')
        > print([next(x) for _ in range(20)])
        ['A', 'B', 'C', 'AA', 'AB', 'AC', 'BA', 'BB', 'BC', 'CA', 'CB', 'CC', 'AAA', 'AAB', ... ]
        

        它从当前字符串生成下一个字符串:

        1. 找出字母表中不是最后一个的倒数第一个字符:例如!= 'Z'

          b) 递增:设置为下一个字母

          c) 将所有后续字符重置为第一个字母字符

        2. 如果没有找到这样的可递增字符,则从所有第一个字母开始,将长度增加1

        可以以(大得多)更大的内存占用为代价编写更易读/更全面的函数,尤其是在生成许多标签的情况下:

        def labels(alphabet=string.ascii_uppercase):
            agenda = deque(alphabet)
            while agenda:
                s = agenda.popleft()
                yield s
                agenda.append([s+c for c in alphabet])
        

        【讨论】:

          【解决方案4】:

          我的解决方案:

          itertools.chain(*[itertools.product(map(chr, range(65,91)), repeat=i) for i in xrange(1, 10)])
          

          请注意魔术数字 10 - 这是列名中的最大字母。

          说明:
          首先将 A-Z 字母创建为列表:

          map(chr, range(65,91))
          

          然后使用 product 来创建组合(长度从 1 开始到 10 结束)

          itertools.product(map(chr, range(65,91)), repeat=i)
          

          最后使用 itertools.chain 将所有这些生成器连接到单个生成器中

          【讨论】:

            猜你喜欢
            • 2017-10-21
            • 2016-02-29
            • 2015-09-11
            • 2023-03-09
            • 1970-01-01
            • 2015-10-24
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多