Повторно используемый код для итерации по различным измерениям массива - PullRequest
1 голос
/ 25 февраля 2020

Скажем, у меня есть N-мерный массив my_array[D1][D2]...[DN]

Для определенного приложения, такого как анализ чувствительности, мне нужно зафиксировать точку p=(d1, d2, ..., dN) и выполнять итерации по каждому измерению за раз. В результате получается

for x1 in range(0, D1):
    do_something(my_array[x1][d2][d3]...[dN])
for x2 in range(0, D2):
    do_something(my_array[d1][x2][d3]...[dN])
.
.
.
for xN in range(0, DN):
    do_something(my_array[d1][d2][d3]...[xN])

Как видите, здесь много дублированного кода. Как я могу сократить объем работы и написать вместо этого какой-нибудь элегантный код?

Например, существует ли какой-либо подход к генерации кода, аналогичный приведенному ниже?

for d in range(0, N):
    iterate along the (d+1)th dimension of my_array, denoting the element as x:
        do_something(x)

Ответы [ 3 ]

0 голосов
/ 25 февраля 2020

Я не понимаю, что такое d1, d2, d3, но, думаю, вы можете сделать что-то вроде этого:

def get_list_item_by_indexes_list(in_list, indexes_list):
    if len(indexes_list) <= 1:
        return in_list[indexes_list[0]]
    else:
        return get_list_item_by_indexes_list(in_list[indexes_list[0]], indexes_list[1:])

def do_to_each_dimension(multi_list, func, dimensions_lens):
    d0_to_dN_list = [l - 1 for l in dimensions_lens] # I dont know what is it
    for dimension_index in range(0, len(dimensions_lens)):
        dimension_len = dimensions_lens[dimension_index]
        for x in range(0, dimension_len):
            curr_d0_to_dN_list = d0_to_dN_list.copy()
            curr_d0_to_dN_list[dimension_index] = x
            func(get_list_item_by_indexes_list(multi_list, curr_d0_to_dN_list))


def do_something(n):
    print(n)

dimensions_lens = [3, 5]
my_array = [
    [1, 2, 3, 4, 5], 
    [6, 7, 8, 9, 10], 
    [11, 12, 13, 14, 15]
    ]

do_to_each_dimension(my_array, do_something, dimensions_lens)

Вывод:

5  10  15  11  12  13  14  15

Этот код повторяет последние столбец и последняя строка двумерного массива.

Теперь, чтобы выполнить итерацию по последней строке каждого измерения трехмерного массива:

dimensions_lens = [2, 4, 3]
my_array = [
    [
        [1, 2, 3], 
        [4, 5, 6], 
        [7, 8, 9], 
        [10, 11, 12]
        ], 
    [
        [13, 14, 15], 
        [16, 17, 18], 
        [19, 20, 21], 
        [22, 23, 24]
        ], 
    ]

do_to_each_dimension(my_array, do_something, dimensions_lens)

Вывод:

12  24  15  18  21  24  22  23  24

(Примечание: не используйте измерения нулевой длины с этим кодом)

0 голосов
/ 25 февраля 2020

Вы можете связываться со строковым представлением доступа к вашему массиву (my_arr[d1][d2]...[dN]) и eval, чтобы впоследствии получить нужные значения. Это довольно «хакерский», но он будет работать на массивах с произвольными измерениями и позволяет указывать индексы в виде списка, обрабатывая доступ к вложенным массивам под капотом, что позволяет получить чистый double для l oop.

def access_at(arr, point):
    # build 'arr[p1][p2]...[pN]'
    access_str = 'arr' + ''.join([f'[{p}]' for p in point])
    return eval(access_str)

Использование этого метода доступа довольно просто:

p = [p1, ..., pN]
D = [D1, ..., DN]
for i in range(N):
    # deep copy p
    pt = p[:]
    for x in range(D[i]):
        pt[i] = x
        do_something(access_at(my_array, pt))
0 голосов
/ 25 февраля 2020

Вы можете использовать numpy .take и сделать что-то вроде следующего. Go через документацию для справки.

https://docs.scipy.org/doc/numpy/reference/generated/numpy.take.html

N = len(my_array)
for i in range(N):
  n = len(my_array(i))
  indices = p
  indices[i] = x[i]
  for j in range(n):
     do_something(np.take(my_array,indices))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...