如何对相同布尔值的块进行分组?

Posted

技术标签:

【中文标题】如何对相同布尔值的块进行分组?【英文标题】:How to group blocks of identical Booleans? 【发布时间】:2018-11-12 16:00:19 【问题描述】:

假设我有以下列表:

a = [True, True, True, False, False, False, False, True, True]

如何通过仅返回 037 或类似以下的分组来对它们进行最佳分组?

[True, True, True]
[False, False, False, False]
[True, True]

背景:我正在尝试在我的 NumPy 数组中找到平稳期,虽然将导数设置为零是一个好的开始,但我仍然需要将数组排序成块。我认为这基本上归结为上述问题。

我查找了 NumPy 和 itertools(试图从问题 NumPy grouping using itertools.groupby performance 中获得解决方案)但我没有成功。我想有人可能会使用itertools.takewhile 和 filtfalse 的组合(请参阅文档here),但我对此并不了解。或者我只是想得太复杂了。

【问题讨论】:

itertools.groupby 无疑是最明显的原生 python 方式来做到这一点,你到底有什么问题?速度、内存还是其他? 技能,我只是没有设法找到使用 itertools.groupby 的解决方案 [list(g) for _,g in itertools.groupby(a)] 创建列表...但我想获取索引不是那么方便,也许是[next(g)[0] for _,g in itertools.groupby(enumerate(a), key=lambda x: x[1])] 【参考方案1】:

我们可以通过切片数组比较来获得索引,它应该在大尺寸列表/数组的性能方面表现良好 -

a_ext = np.r_[~a[0],a]
out = np.flatnonzero(a_ext[:-1]!=a_ext[1:])

作为单行,我们可以使用np.diff + np.flatnonzero -

np.flatnonzero(np.diff(np.r_[~a[0],a]))
# compact alternative : np.where(np.diff(np.r_[~a[0],a]))[0]

【讨论】:

@Idlehands 来自问题“我正在尝试在 numpy 数组中找到高原”。所以不,我不这么认为。 @Idlehands 我已经看到,它在寻找大型数据的性能时很有用。所以,这取决于我认为的要求。 @Eulenfuchswiesel 感谢您的编辑建议。已编辑。【参考方案2】:

最简单的方法可能是这样的:

a = [True, True, True, False, False, False, False, True, True]

res = [0] + [i+1 for i, (x, y) in enumerate(zip(a, a[1:])) if x!=y]
print(res)  # -> [0, 3, 7]

groupby 解决方案而言,您可以这样做:

from itertools import groupby

groups = [list(g) for _, g in groupby(a)]
print(groups)  # -> [[True, True, True], [False, False, False, False], [True, True]]

【讨论】:

【参考方案3】:

您可以使用itertools.groupby 完全做到这一点:

给定

import itertools as it

a = [True, True, True, False, False, False, False, True, True]

代码

[list(g)[0][0] for _, g in it.groupby(enumerate(a), key=lambda x: x[-1])]
# [0, 3, 7]

详情

这是您可迭代的groupby 的输出:

[(k, list(g)) for k, g in it.groupby(a)]
# [(True, [True, True, True]),
#  (False, [False, False, False, False]),
#  (True, [True, True])]

我们可以将每个组的每个项目 (g) 枚举为元组,并按每个元组中的最后一个索引进行分组:

[list(g) for k, g in it.groupby(enumerate(a), key=lambda x: x[-1])]
# [[(0, True), (1, True), (2, True)],
#  [(3, False), (4, False), (5, False), (6, False)],
#  [(7, True), (8, True)]]

现在我们想要第一个项目 ([0]) 和第一个位置 ([0]) 来获取每个组的索引。

[next(g)[0] ...] 中的Chris_Rands' suggestion 更加干净。

另请参阅this post,了解如何使用groupby

【讨论】:

以上是关于如何对相同布尔值的块进行分组?的主要内容,如果未能解决你的问题,请参考以下文章

一种返回布尔值的方法,该布尔值标识两个数组的值是不是相同

始终返回相同布尔值的 Python 函数

错误:使用带有布尔值的 BLoC_pattern 时出现“错误状态:无元素”

python-布尔值的加法运算

Java同时覆盖具有相同值的原语

如何检查具有布尔值的复选框