如何统计列表末尾的出现次数

4
我想在Python中统计列表末尾相同的出现次数。这很容易做到,但我也对您的解决方案感兴趣。该列表只能包含'1'或'2'项。结果必须在[3、4、5]之间。如果小于2,则退出;如果大于5,则返回5。
示例: 假设有以下列表:
  L = [1,1,2]
  Result: None (quit)

  L = [1,2,1,1]
  Result: None (quit)

  L = [1,2,1,1,1]
  Result: 3

  L = [1,1,2,2,2,2]
  Result: 4

  L = [1,2,1,1,1,1,1,1]
  Result: 5

有趣的任务。我喜欢解决这样的难题。 :) - pemistahl
我喜欢这种问题的答案,因为总会有人能用一行代码解决。这让我意识到我应该更深入地学习语言的语法 :) - Mejmo
是的,这确实令人惊讶。但正如您从答案中所看到的,这并不总是推荐的一行代码方式。用水平长度替换垂直长度并不一定简化代码。 ;) - pemistahl
5个回答

2

我会承担提供易读答案的无聊工作。;) 它适用于所有类型的元素,而不仅仅是 12

In [1]: def list_end_counter(lst):
  ....:     counter = 0
  ....:     for elem in reversed(lst):
  ....:         if elem == lst[-1]:
  ....:             counter += 1
  ....:         else:
  ....:             break
  ....:     if counter < 3:
  ....:         return None
  ....:     elif counter > 5:
  ....:         return 5
  ....:     return counter

稍作修改以节省一些行:

In [1]: def list_end_counter(lst):
  ....:     def stop():
  ....:         raise StopIteration()
  ....:     counter = sum(1 if elem == lst[-1] else stop() for elem in reversed(lst))
  ....:     return None if counter < 3 else 5 if counter > 5 else counter

两者都可以得到正确的结果:

In [2]: print list_end_counter([1,1,2])
None

In [3]: print list_end_counter([1,2,1,1])
None

In [4]: print list_end_counter([1,2,1,1,1])
3

In [5]: print list_end_counter([1,1,2,2,2,2])
4

In [6]: print list_end_counter([1,2,1,1,1,1,1,1])
5

我相信这是解决这类问题的一种主题方式。 - Akavall
@Akavall 你所说的“thematic”具体是什么意思? - pemistahl
我想我的意思是这类似于伪代码;你可以在任何语言中使用这个想法,+1。 - Akavall
@Akavall 是的,我非常喜欢 Python 的伪代码风格。这就是为什么我更喜欢编写易读的代码而不是节省代码行数。看到其他答案时,我感到很放心。;) - pemistahl

2

搞笑的一句话回答:

def countOccurencesAtTheEndOfTheList(L):
    return (lambda num: None if num <= 2 else min(5, num))(len(L) if all(map(lambda x: x == L[-1], L)) else len(L) - 1 - [idx for idx, x in enumerate(L) if x != L[-1]][-1])

print countOccurencesAtTheEndOfTheList([1,1,2])
print countOccurencesAtTheEndOfTheList([1,2,1,1])
print countOccurencesAtTheEndOfTheList([1,2,1,1,1])
print countOccurencesAtTheEndOfTheList([1,1,2,2,2,2])
print countOccurencesAtTheEndOfTheList([1,2,1,1,1,1,1,1])

输出:

None
None
3
4
5

说明:

[idx for idx, x in enumerate(L) if x != L[-1]] 获取L中与最后一个元素不相同的每个元素的索引。
[idx for idx, x in enumerate(L) if x != L[-1]][-1] 获取最右边的一个与最后一个元素不匹配的元素的索引。仅当列表中的所有元素都不相同时才有效。
len(L) - 1 - [上一行] 获取列表末尾与最后一个元素匹配的元素数,如果列表中的所有元素都不相同,则成立。
all(map(lambda x: x== L[-1], L) 仅当列表中的所有元素都相同时返回True。
len(L) if [上一行] else [上上行] 获取列表末尾与最后一个元素匹配的元素数,无论列表中的所有元素是否相同。
lambda num: None if num <= 2 else min(5, num) 如果值太低,则返回None,并将最大可能值限制为5。

警告:仅供娱乐目的。请勿编写此类代码。


哈哈,为娱乐加一! - RocketDonkey

1
您可以尝试使用itertools.groupby,利用它会将未排序的键分别分组的特性(这里返回False仅为展示输出结果,您可以根据需要更改)。使用groupby,您将获得一个可迭代对象,其形式为(key, values),其中values是另一个包含与该键相关的所有值的可迭代对象。在这种情况下,我们不关心键(因此使用_),我们将values转换为列表,然后取其长度(这将导致长度列表看起来像[1, 1, 2],例如[1, 2, 1, 1])。然后,我们从该列表中取出最后一项,该项将表示最后一个元素重复的次数。从那里开始,我们应用哪个值返回的逻辑:

In [1]: from itertools import groupby

In [2]: def my_func(l):
   ...:     val = [len(list(g)) for _, g in groupby(l)][-1]
   ...:     if val < 3:
   ...:         return False
   ...:     return min(val, 5)
   ...: 

In [3]: 

In [4]: L = [1,1,2]

In [5]: my_func(L)
Out[5]: False

In [6]: L = [1,2,1,1]

In [7]: my_func(L)
Out[7]: False

In [8]: L = [1,2,1,1,1]

In [9]: my_func(L)
Out[9]: 3

In [10]: L = [1,1,2,2,2,2]

In [11]: my_func(L)
Out[11]: 4

In [12]: L = [1,2,1,1,1,1,1,1]

In [13]: my_func(L)
Out[13]: 5

我脑海中浮现了一个问题..如果我想使用自定义迭代器(列表不包含int,而是其他包含1/2值的对象),那么groupby语句应该是什么样子的呢?我的意思是自定义迭代器-不通过重载列表的__iter__实现的迭代器。谢谢。 - Mejmo
@备忘录稍后会详细介绍一下,但简单来说,groupby在分组方面非常灵活。您可以通过提供key参数来使用此功能,该参数确定应如何对可迭代对象进行分组。在您的情况下,您需要提供一个函数,该函数将返回用于区分对象的任何元素。这可能听起来有点复杂,所以我稍后会更新一个例子 :) - RocketDonkey
值1/2被隐藏在L[i].object1.attr1下。 - Mejmo
好的,count = [len(list(g)) for _, g in groupby(l, lambda x: x.object1.attr1)][-1] 已经完成了。非常感谢。 - Mejmo
@Mejmo Ha,嗯,你学得很快,做得很好 :) 有一件事需要注意的是,通常你需要对数据进行排序才能获得所需的行为 - 这恰好是较少见的情况之一,你可以利用非排序行为。很高兴你解决了问题,如果还有其他问题需要帮助,请随时联系我。 - RocketDonkey

1

这里有另一个想法:

def count(l):
    n = l[::-1].index([2,1][l[-1] - 1])
    return min(n, 5) if n > 2 else None

print count([1,1,2])
print count([1,2,1,1])
print count([1,2,1,1,1])
print count([1,1,2,2,2,2])
print count([1,2,1,1,1,1,1,1])
无
无
3
4
5

哈,我喜欢这个比我的更多,+1(总是喜欢使用聪明的逻辑解决方案 :))。 - RocketDonkey
有趣,但不太易读。 ;) (至少对我来说是这样。) - pemistahl
@PeterStahl 嗯,这在很大程度上依赖于列表仅包含 12。 :P - arshajii

0

列表的“index”方法可用于搜索。

我假设如果列表全部为1,则希望得到与在该列表前加入单个2时相同的结果;如果全部为2,则希望得到与在该列表前加入1时相同的结果...

def mejmo_count( lst ):

    if len(lst) >= 3:          # otherwise answer is None
       tail = lst[-2:-6:-1]    # extract last part, reversed (omit final)
       x = 3-lst[-1]           # search for this..
       n = (tail + [x]).index(x) # find the first x (sentinel found if not present)
       if n >= 2:             # n can be 0..4 here
           return n+1
    return None

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接