简体   繁体   English

Pythonic确定当前元素是否是生成器的第一个或最后一个元素的方法?

[英]Pythonic way of determining if the current element is the first or last element of a generator?

I am going through a generator, whats the Pythonic way of determining if the current element is the first or last element of a generator, given that they need special care? 我正在经历一个生成器,为什么他们需要特别小心,以Pythonic方式确定当前元素是否是生成器的第一个或最后一个元素?

thanks 谢谢

basically generating tags, so i have items like 基本上生成标签,所以我有像

<div class="first">1</div>
<div>...</div>
<div class="last">n</div>

so i would like to keep the last item in loop? 所以我想保持循环中的最后一项?

Here's an enumerate-like generator that skips ahead one; 这是一个类似枚举的生成器,可以向前跳过一个; it returns -1 for the last element. 它为最后一个元素返回-1。

>>> def annotate(gen):
...     prev_i, prev_val = 0, gen.next()
...     for i, val in enumerate(gen, start=1):
...         yield prev_i, prev_val
...         prev_i, prev_val = i, val
...     yield '-1', prev_val
>>> for i, val in annotate(iter(range(4))):
...     print i, val
... 
0 0
1 1
2 2
-1 3

It can't tell whether the generator passed to it is "fresh" or not, but it still tells you when the end is nigh: 它无法判断传递给它的发电机是否“新鲜”,但它仍然告诉你何时结束:

>>> used_iter = iter(range(5))
>>> used_iter.next()
0
>>> for i, val in annotate(used_iter):
...     print i, val
... 
0 1
1 2
2 3
-1 4

Once an iterator is used up, it raises StopIteration as usual. 一旦迭代器用完,就像往常一样引发StopIteration

>>> annotate(used_iter).next()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in annotate
StopIteration

The way that I do this is similar to some of the other answers here - but I do it this way, as a matter of preference. 我这样做的方式类似于其他一些答案 - 但我这样做,作为优先选择。 Maybe it will suit your preferences too. 也许它也适合你的喜好。

With my function below, I can write code like this: 使用下面的函数,我可以编写如下代码:

values = [10, 11, 12, 13]
for i, val, isfirst, islast in enumerate2(values):
  if isfirst:
    print 'BEGIN...', val
  elif islast:
    print val, '... END'
  else:
    print val

Here is the function definition: 这是函数定义:

def enumerate2(iterable_):
  it = iter(iterable_)
  try:
    e = it.next()
    isfirst = True
    i = 0
    try:
      while True:
        next_e = it.next()
        yield (i, e, isfirst, False)
        i += 1
        isfirst = False
        e = next_e
    except StopIteration:
      yield (i, e, isfirst, True)
  except StopIteration:
    pass

For the first, use a flag to tell whether or not you've processed any. 对于第一个,使用标志来判断您是否已处理任何。 For the last, hold the next value in a variable, and if there are no more then that's the last one. 最后,在变量中保存下一个值,如果没有,那么这是最后一个。

Well, as for the first element: 那么,至于第一个元素:

for n, item in enumerate(generator()):
  if n == 0:
    # item is first
# out of the loop now: item is last

Turn it into a sequence, example: 把它变成一个序列,例如:

>>> gen = (x for x in range(5))
>>> L = list(gen)
>>> L[0]
0
>>> L[-1]
4
>>>

If you need to do this during the loop: 如果您需要在循环期间执行此操作:

>>> gen = (x for x in range(5))
>>> L = list(gen)
>>> for idx, item in enumerate(L):
...    if idx == 0:
...        print(u'{item} is first'.format(item=item))
...    if idx == len(L) - 1:
...        print(u'{item} is last'.format(item=item))
...
0 is first
4 is last
>>>

Clearly, this is not the solution, if you are the one who created the generator, and need it to stay that way (for memory savings), but if you don't care, this is more Pythonic per se than setting flags (which is implicit at best, sine it relies on the last element during iteration persisting), and enumerate won't get you any closer to finding the last element. 显然,这不是解决方案,如果是创建生成器的人,并且需要它保持这种方式(为了节省内存),但是如果你不在乎,这比设置标志更加Pythonic本身(最好是隐式的,正则它依赖于迭代持久化过程中的最后一个元素),并且enumerate不会让你更接近找到最后一个元素。

当然,它违反了所有生成器的优点,但如果你的iterable不大,你应该使用:

list(gener)[1:-1]

If you're concerned about potentially large collections built dynamically, so that you don't want to temporarily place it into a single data structure, here's a different way: 如果您担心动态构建的潜在大型集合,那么您不希望将其暂时放入单个数据结构中,这是一种不同的方式:

FLAGMASK_FIRST = 1
FLAGMASK_LAST = 2

def flag_lastfirst(collection):
    first_flag = FLAGMASK_FIRST
    first = True
    index = 0
    for element in collection:
        if not first:
            yield index, first_flag, current
            index += 1
            first_flag = 0
        current = element
        first = False
    if not first:
        yield index, first_flag | FLAGMASK_LAST, current

l = [1, 2, 3, 4]
for k in flag_lastfirst(l):
    print(k)

The function will produce a sequence of tuples, one for each element from the original collection. 该函数将生成一系列元组,每个元素对应一个原始集合。

The contents of the tuple: 元组的内容:

  • t[0] = 0-based index t[0] =基于0的索引
  • t[1] = bitwise flags, FLAGMASK_FIRST is present if the element is the first element, FLAGMASK_LAST is present if the element is the last element t[1] =按位标志,如果元素是第一个元素,则存在FLAGMASK_FIRST,如果元素是最后一个元素,则存在FLAGMASK_LAST
  • t[2] = The original element from the original collection t[2] =原始集合中的原始元素

Sample output from the code above: 上面代码的示例输出:

 +-- 0-based index
 v
(0, 1, 1)
(1, 0, 2)
(2, 0, 3)
(3, 2, 4)
    ^  ^
    |  +-- the element from the original collection
    |
    +-- 1 means first, 2 means last,
        3 means both first and last, 0 is everything else

I'm sure there are nicer ways to build this kinda thing, but this is my contribution anyway. 我确信有更好的方法可以构建这样的东西,但无论如何这是我的贡献。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Pythonic方式获取序列的第一个和最后一个元素 - Pythonic way to get the first AND the last element of the sequence 基于生成器中最后一个元素获取变量的大多数 pythonic 方法? - Most pythonic way to get variable based on last element in generator? 检测“for”循环中最后一个元素的pythonic方法是什么? - What is the pythonic way to detect the last element in a 'for' loop? 进行设置差异时忽略最后一个元素的 Pythonic 方式 - Pythonic way of ignoring the last element when doing set difference 在for循环中跳到列表的最后一个元素的pythonic方法是什么? - What is the pythonic way to skip to the last element of a list in a for loop? 向量化pythonic方法来获取大于当前元素的元素数 - Vectorized pythonic way to get count of elements greater than current element 用Pythonic方法获取具有特定名称的第一个XML元素的值 - Pythonic way to get value of first XML element with specific name 获取数组的一部分以及numpy中的第一个元素(以pythonic方式) - Get part of array plus first element in numpy (In a pythonic way) 获取多维numpy数组的第一个元素的pythonic方法 - pythonic way to get first element of multidimensional numpy array Pythonic方式的递归发生器? - Recursive generator in Pythonic way?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM