计算范围内唯一元素数量的有效方法?

时间:2017-07-20 13:49:46

标签: python performance numpy set range

我需要计算一组给定范围内的唯一元素的数量。我的输入是这些范围的起点和终点坐标,我执行以下操作。

>>>coordinates
 [[7960383, 7961255],
 [15688414, 15689284],
 [19247797, 19248148],
 [21786109, 21813057],
 [21822367, 21840682],
 [21815951, 21822369],
 [21776839, 21783355],
 [21779693, 21786111],
 [21813097, 21815959],
 [21776839, 21786111],
 [21813097, 21819613],
 [21813097, 21822369]]
 [21813097, 21822369]]
>>>len(set(chain(*[range(i[0],i[1]+1) for i in coordinates])))   #here chain is from itertools

问题是它不够快。这需要在我的机器上花费3.5ms(使用%timeit)(购买新计算机不是一种选择),因为我需要在数百万台上执行此操作,所以速度并不快。

有关如何证明这一点的任何建议吗?

编辑:行数可以变化。在这种情况下,有12行。但我不能给它任何上限。

3 个答案:

答案 0 :(得分:5)

你可以只取坐标之间的差值,然后减去重叠:

coordinates =[
    [ 7960383,  7961255],
    [15688414, 15689284],
    [19247797, 19248148],
    [21776839, 21786111],
    [21813097, 21819613],
    [21813097, 21822369]
]

# sort by increasing first coordinate, and if equal, by second:
coordinates.sort()

count = 0
prevEnd = 0
for start, end in coordinates:
    if end > prevEnd: # ignore a range that is sub-range of the previous one
        count += end - max(start, prevEnd)
        prevEnd = end

print (count)

这在空间和时间上都很便宜。

包含的末端坐标

编辑完成后,您希望第二个坐标具有包容性。在那种情况下"纠正"像这样的计算:

count = 0
prevEnd = -1
for start, end in coordinates:
    if end > prevEnd: # ignore a range that is sub-range of the previous one
        count += end - max(start - 1, prevEnd)
        prevEnd = end

答案 1 :(得分:0)

使用NumPy,您可以:

import numpy as np

coordinates = ...
nums = np.concatenate([np.arange(start, end) for start, end in coordinates], axis=0)
num_unique = len(np.unique(nums))

更新

如果你能负担得到一个矩阵,其行数与coordinates的数量相同,列数与最大数量相同,则另一个选项是:

import numpy as np

coordinates = np.asarray(coordinates)
nums = np.tile(np.arange(np.max(coordinates)), (len(coordinates), 1))
m = (nums >= coordinates[:, :1]) & (nums < coordinates[:, 1:])
num_unique = np.count_nonzero(np.logical_or.reduce(m, axis=0))

答案 2 :(得分:0)

也许这更好?

<select
    onChange={props.onChange}
    id={props.id}
    className={props.style || "form-control"}>
    {!props.defaultOption ?
        <option value="" selected>Select</option> :
        <option value={props.defaultOptionValue} disabled selected>{props.defaultOption}</option>}
    {props.options.map((item, i) => {
        if (item.id === props.defaultOptionValue) return false;
        return <option key={i} value={item.id}>{item.name}</option>
    })}
</select>