加快第二个数组中数组元素的搜索

时间:2019-09-25 23:09:33

标签: python arrays performance numpy

我有一个非常简单的操作,涉及两个不那么大的数组:

  1. 对于第一个(较大)数组中位于Map<String, Image> imageRepository = new HashMap<>(); // to be filled PickUpItem createItem(String type, int x, int y) { Image itemImage = imageRepository.getOrDefault(type, yourDefaultImg); return new PickUpItem(itemImage, x, y); } public void spawnPickUpItem(String type, int x, int y) { PickUpItem pickUpItem = createItem(String type, int x, int y); // further logic . . . } 位置的每个元素
  2. 查找第二个(较小的)数组中是否存在
  3. 如果确实如此,请在第二个数组中找到其索引:i
  4. 在第四个数组(与第二个数组相同的长度)的位置j和第四个数组(与第二个数组相同的长度)的位置i中存储从第三个数组(与第一个数组相同的长度)中提取的浮点数

下面的j块可以工作,但是对于不是那么大的数组(> 10000)来说,非常变慢。

可以更快地实现此实现吗?

for

2 个答案:

答案 0 :(得分:1)

为捍卫我的方法,以下是权威性的实施方式:

import itertools as it

def pp():
    la,lb = len(ids_a),len(ids_b)
    ids = np.fromiter(it.chain(ids_a,ids_b),'<S6',la+lb)
    unq,inv = np.unique(ids,return_inverse=True)
    vals = np.empty(la,vals_in_a.dtype)
    vals[inv[:la]] = vals_in_a
    return vals[inv[la:]]

(juanpa()==pp()).all()
# True

timeit(juanpa,number=100)
# 3.1373191522434354
timeit(pp,number=100)
# 2.5256317732855678

也就是说,@ juanpa.arrivillaga的建议也可以更好地实现:

import operator as op

def ja():
    return op.itemgetter(*ids_b)(dict(zip(ids_a,vals_in_a)))

(ja()==pp()).all()
# True
timeit(ja,number=100)
# 2.015202699229121

答案 1 :(得分:0)

我尝试了juanpa.arrivillaga和Paul Panzer的方法。第一个是迄今为止最快的。这也是最简单的。第二种方法比我最初的方法要快,但比第一种方法要慢得多。它还有一个缺点,该行vals[inv_a] = vals_in_a将浮点数存储到U5数组中,从而将它们转换为字符串。可以在结尾将其转换回浮点数,但是我会丢失数字(除非我当然缺少明显的东西。

以下是实现:

def juanpa():
    dict_ids_b = {_: i for i, _ in enumerate(ids_b)}
    for i, id_a in enumerate(ids_a):
        try:
            vals_in_b[dict_ids_b[id_a]] = vals_in_a[i]
        except KeyError:
            pass

    return vals_in_b


def Paul():
    # 1) concatenate ids_a and ids_b
    ids_ab = ids_a + ids_b
    # 2) apply np.unique with keyword return_inverse=True
    vals, idxs = np.unique(ids_ab, return_inverse=True)
    # 3) split the inverse into inv_a and inv_b
    inv_a, inv_b = idxs[:len(ids_a)], idxs[len(ids_a):]
    # 4) map the values to match the order of uniques: vals[inv_a] = vals_in_a
    vals[inv_a] = vals_in_a
    # 5) use inv_b to pick the correct values: result = vals[inv_b]
    vals_in_b = vals[inv_b].astype(float)

    return vals_in_b