这是我发布的here问题的后续问题,但这是一个非常不同的问题,所以我想我会单独发布。
我有一个Python脚本,它读取一个非常大的数组,我需要优化每个元素的操作(参见引用的SO问题)。我现在需要将输出数组拆分为两个独立的数组。
我有代码:
output = [True if (len(element_in_array) % 2) else False for element_in_array in master_list]
输出一个长度为len(master_list)
的数组,由True或False组成,具体取决于element_in_array
的长度是奇数还是偶数。我的问题是我需要将master_list
拆分为两个数组:一个数组包含与element_in_array
中的True
元素对应的output
,另一个包含element_in_array
元素1}}对应False
中的output
元素。
这可以通过append
这样的传统数组运算符来实现,但我需要尽可能优化和尽可能快。我的master_list
中有数百万个元素,所以有没有办法在不直接循环master_list
并使用append
创建两个新数组的情况下完成此操作。
任何建议都将不胜感激。 谢谢!
答案 0 :(得分:0)
您可以使用itertools.compress
:
>>> from itertools import compress, imap
>>> import operator
>>> lis = range(10)
>>> output = [random.choice([True, False]) for _ in xrange(10)]
>>> output
[True, True, False, False, False, False, False, False, False, False]
>>> truthy = list(compress(lis, output))
>>> truthy
[0, 1]
>>> falsy = list(compress(lis, imap(operator.not_,output)))
>>> falsy
[2, 3, 4, 5, 6, 7, 8, 9]
如果您想要更快的解决方案,请转到NumPy,此外它还允许我们根据布尔数组进行数组过滤:
>>> import numpy as np
>>> a = np.random.random(10)*10
>>> a
array([ 2.94518349, 0.09536957, 8.74605883, 4.05063779, 2.11192606,
2.24215582, 7.02203768, 2.1267423 , 7.6526713 , 3.81429322])
>>> output = np.array([True, True, False, False, False, False, False, False, False, False])
>>> a[output]
array([ 2.94518349, 0.09536957])
>>> a[~output]
array([ 8.74605883, 4.05063779, 2.11192606, 2.24215582, 7.02203768,
2.1267423 , 7.6526713 , 3.81429322])
时间比较:
>>> lis = range(1000)
>>> output = [random.choice([True, False]) for _ in xrange(1000)]
>>> a = np.random.random(1000)*100
>>> output_n = np.array(output)
>>> %timeit list(compress(lis, output))
10000 loops, best of 3: 44.9 us per loop
>>> %timeit a[output_n]
10000 loops, best of 3: 20.9 us per loop
>>> %timeit list(compress(lis, imap(operator.not_,output)))
1000 loops, best of 3: 150 us per loop
>>> %timeit a[~output_n]
10000 loops, best of 3: 28.7 us per loop
答案 1 :(得分:0)
如果您可以使用NumPy,这将更加简单。并且,作为奖励,它也会快得多,并且它将使用更少的内存来存储您的巨型阵列。例如:
>>> import numpy as np
>>> import random
>>> # create an array of 1000 arrays of length 1-1000
>>> a = np.array([np.random.random(random.randint(1, 1000))
for _ in range(1000)])
>>> lengths = np.vectorize(len)(a)
>>> even_flags = lengths % 2 == 0
>>> evens, odds = a[even_flags], a[~even_flags]
>>> len(evens), len(odds)
(502, 498)
答案 2 :(得分:0)
您可以尝试使用groupby
中的itertools
功能。关键功能是确定元素长度是否均匀的函数。由groupby
返回的迭代器由键值元组组成,其中key是键函数返回的值(此处为True
或False
),值为一系列项目所有股
同样的关键。创建一个字典,将键函数返回的值映射到列表,并且可以使用初始迭代器中的一组值扩展相应的列表。
trues = []
falses = []
d = { True: trues, False: falses }
def has_even_length(element_in_array):
return len(element_in_array) % 2 == 0
for k, v in itertools.groupby(master_list, has_even_length):
d[k].extend(v)
groupby
的文档说您通常希望确保列表按键功能返回的相同键排序。在这种情况下,可以保持未分类;你将只有groupby
返回的迭代器返回的东西,因为序列中可能存在许多交替的真/假集。