F'x*_*F'x 54 python filter data-partitioning
假设我有一个列表和一个过滤功能.使用类似的东西
>>> filter(lambda x: x > 10, [1,4,12,7,42])
[12, 42]
Run Code Online (Sandbox Code Playgroud)
我可以得到符合标准的元素.是否有一个我可以使用的函数可以输出两个列表,一个元素匹配,剩下的元素之一?我可以filter()两次调用该函数,但这有点难看:)
编辑:元素的顺序应该是守恒的,我可能多次使用相同的元素.
Mar*_*ers 46
试试这个:
def partition(pred, iterable):
trues = []
falses = []
for item in iterable:
if pred(item):
trues.append(item)
else:
falses.append(item)
return trues, falses
Run Code Online (Sandbox Code Playgroud)
用法:
>>> trues, falses = partition(lambda x: x > 10, [1,4,12,7,42])
>>> trues
[12, 42]
>>> falses
[1, 4, 7]
Run Code Online (Sandbox Code Playgroud)
在itertools食谱中还有一个实现建议:
from itertools import filterfalse, tee
def partition(pred, iterable):
'Use a predicate to partition entries into false entries and true entries'
# partition(is_odd, range(10)) --> 0 2 4 6 8 and 1 3 5 7 9
t1, t2 = tee(iterable)
return filterfalse(pred, t1), filter(pred, t2)
Run Code Online (Sandbox Code Playgroud)
配方来自Python 3.x文档.在Python 2.x filterfalse被调用ifilterfalse.
Mar*_*riy 21
>>> def partition(l, p):
... return reduce(lambda x, y: (x[0]+[y], x[1]) if p(y) else (x[0], x[1]+[y]), l, ([], []))
...
>>> partition([1, 2, 3, 4, 5], lambda x: x < 3)
([1, 2], [3, 4, 5])
Run Code Online (Sandbox Code Playgroud)
上面的代码有点丑陋但速度更快的版本:
def partition(l, p):
return reduce(lambda x, y: x[0].append(y) or x if p(y) else x[1].append(y) or x, l, ([], []))
Run Code Online (Sandbox Code Playgroud)
这是第二次编辑,但我认为这很重要:
def partition(l, p):
return reduce(lambda x, y: x[not p(y)].append(y) or x, l, ([], []))
Run Code Online (Sandbox Code Playgroud)
第二个和第三个与迭代的上层一样快,但代码较少.
你可以看看django.utils.functional.partition解决方案:
def partition(predicate, values):
"""
Splits the values into two sets, based on the return value of the function
(True/False). e.g.:
>>> partition(lambda x: x > 3, range(5))
[0, 1, 2, 3], [4]
"""
results = ([], [])
for item in values:
results[predicate(item)].append(item)
return results
Run Code Online (Sandbox Code Playgroud)
在我看来,这是这里提出的最优雅的解决方案。
这部分没有记录,只能在https://docs.djangoproject.com/en/dev/_modules/django/utils/functioning/上找到源代码
小智 6
我认为groupby可能在这里更相关:
http://docs.python.org/library/itertools.html#itertools.groupby
例如,将列表拆分为奇数和偶数(或者可以是任意数量的组):
>>> l=range(6)
>>> key=lambda x: x % 2 == 0
>>> from itertools import groupby
>>> {k:list(g) for k,g in groupby(sorted(l,key=key),key=key)}
{False: [1, 3, 5], True: [0, 2, 4]}
Run Code Online (Sandbox Code Playgroud)
Run Code Online (Sandbox Code Playgroud)def partition(pred, iterable): trues = [] falses = [] for item in iterable: if pred(item): trues.append(item) else: falses.append(item) return trues, falses
是最简单,最快的。
所建议的不同方法可以大致分为三类,
lis.append,返回2元组列表,lis.append 以功能性方法为中介,返回2元组的列表,itertools优质文档中提供的规范配方,返回一个2元组的发电机(从广义上讲)。这是三种技术的原始实现,首先是功能性方法,然后itertools是直接列表操作的两种不同实现,最后一种选择是使用False零,这True是一个技巧。
请注意,这是Python3(因此reduce来自),functools并且OP要求一个元组,(positives, negatives)但我的实现都返回(negatives, positives)…
$ ipython
Python 3.6.2 |Continuum Analytics, Inc.| (default, Jul 20 2017, 13:51:32)
Type 'copyright', 'credits' or 'license' for more information
IPython 6.1.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]: import functools
...:
...: def partition_fu(p, l, r=functools.reduce):
...: return r(lambda x, y: x[p(y)].append(y) or x, l, ([], []))
...:
In [2]: import itertools
...:
...: def partition_it(pred, iterable,
...: filterfalse=itertools.filterfalse,
...: tee=itertools.tee):
...: t1, t2 = tee(iterable)
...: return filterfalse(pred, t1), filter(pred, t2)
...:
In [3]: def partition_li(p, l):
...: a, b = [], []
...: for n in l:
...: if p(n):
...: b.append(n)
...: else:
...: a.append(n)
...: return a, b
...:
In [4]: def partition_li_alt(p, l):
...: x = [], []
...: for n in l: x[p(n)].append(n)
...: return x
...:
Run Code Online (Sandbox Code Playgroud)
我们需要一个谓词来应用到我们的列表以及要对其进行操作的列表(再次,粗略地说)。
In [5]: p = lambda n:n%2
In [6]: five, ten = range(50000), range(100000)
Run Code Online (Sandbox Code Playgroud)
为了克服测试itertools方法的问题,joeln于13年10月31日在6:17报告
废话。您已经计算了在
filterfalse和中构造生成器所花费的时间filter,但尚未遍历输入或调用pred一次!itertools配方的优点 在于它不会实现任何列表,也不会在输入中超出必要的范围。它的通话pred频率是Byers等人的两倍,几乎是其两倍。
我想到了一个空循环,它仅实例化了由不同分区函数返回的两个可迭代对象中的所有元素对。
首先,我们使用两个固定列表来了解隐含的过载(使用非常方便的IPython的魔术%timeit)
In [7]: %timeit for e, o in zip(five, five): pass
4.21 ms ± 39.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
Run Code Online (Sandbox Code Playgroud)
接下来,我们使用不同的实现,一个接一个
In [8]: %timeit for e, o in zip(*partition_fu(p, ten)): pass
53.9 ms ± 112 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [9]: %timeit for e, o in zip(*partition_it(p, ten)): pass
44.5 ms ± 3.84 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [10]: %timeit for e, o in zip(*partition_li(p, ten)): pass
36.3 ms ± 101 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [11]: %timeit for e, o in zip(*partition_li_alt(p, ten)): pass
37.3 ms ± 109 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [12]:
Run Code Online (Sandbox Code Playgroud)
最简单的方法也是最快的一种。
使用这个x[p(n)]技巧是毫无用处的,因为在每一步中您都必须为数据结构建立索引,从而给您带来一点点损失–但是,很高兴知道您是否想在python化过程中说服幸存者。
功能的方法,即操作性地等同于替代append实施方式中,是〜50%比较慢,这可能是由于这样的事实,我们有一个额外的(W / R到谓词求值)函数调用为每个列表元素。
该itertools方法具有(常规)优势?没有实例化潜在的大列表,并且?如果您脱离使用者循环,则不会完全处理输入列表,但是当我们使用它时,它会变慢,因为需要在谓词的两端应用谓词。tee
我爱上object.mutate() or object了Marii
在他们的回答中暴露出来的惯用语,它显示了解决问题的实用方法-恐怕迟早会滥用它。
[1]截至今天,2017年9月14日,该投票被接受并获得最多投票-但是,对于我的这个回答,我当然寄予了最高的希望!
| 归档时间: |
|
| 查看次数: |
16294 次 |
| 最近记录: |