2015-02-19 4 views
4

Я застреваю, казалось бы, легкой проблемой, может кто-то помочь?Python: суммирование по всем перестановкам

У меня есть два списка: a и b. Я могу назвать элементы списка a[i][j], где 0<i<100 и 0<j<100.

Я хочу найти все a[i][j] - b[k][l], где 0<i<100, 0<j<100, 0<k<100 и 0<l<100. А затем выполните суммирование по всем перестановкам из i, j, k, l.

Кто-нибудь знает элегантный простой способ этого?

+0

Вы пробовали 'itertools.permutations'? – Kevin

+0

Вы написали, что хотите найти «все a [i] [j] - b [k] [l], где 0

+0

Если я правильно понимаю результат, то '100 * 100 * (сумма (sa) для sa в a) - сумма (сумма (sb) для sb в b))'. Каждый элемент подсчитывается 10000 раз, а от «a» с положительным знаком, из «b» с отрицательным. – zch

ответ

3
import itertools 
sum(a[i][j] - b[k][l] for i, j, k, l in itertools.product(range(1, 100), repeat=4)) 

itertools.product эквивалентно вложенной for петли. Он будет проходить через каждые кортеж от (1, 1, 1, 1) до (99, 99, 99, 99). Это пропустит нуль, о котором вы, кажется, попросили.

+0

Кроме того, еще один вопрос .. можно ли вызывать эти значения 'a [i] [j] - b [k] [l]' как say 's (i, j, k, l)' или 's [I] [J] [K] [L] '?? – Panchi

+0

Первый, вероятно, будет легче, чем последний.Просто определите функцию, которая возвращает соответствующие значения (например, lambda i, j, k, l: a [i] [j] - b [k] [l] '). Возможна поддержка 's [i] [j] [k] [l]', но она требует отрезвления классов наиболее раздражающим образом. – Kevin

0

Попробуйте создать декартовы производные диапазонов массивов, чтобы получить индексы.

import itertools 

cprod = itertools.product(range(1, 100, 1), range(1, 100, 1), range(1, 100, 1), range(1, 100, 1)) 
result = sum([a[cp[0]][cp[1] - b[cp[2]][cp[3] for cp in cprod]) 
2

Это способ быстрее:

(sum(map(sum, a)) - sum(map(sum, b))) * len(a) * len(b) 

Поскольку вы расчета суммы общей разности массивов. Он будет работать в O (n), но ответ Кевина, использующий itertools, находится в O (n^2).

я не доказал это (редактировать: here's a proof outline), протестирован только с помощью двух случайных 100x100 массивов, но это отчасти интуитивно, если вы об этом думаете.

Код, как указано Кевином, предположил, что ваши массивы 100x100 и будут включать в себя 0. Я предположил, что вы просто хотели использовать два массива 100x100 и получили обозначение, немного испорченное - если вы действительно хотите пропустить 0 и не знаете размер массива, то вы можете использовать следующий фрагмент кода вместо:

from itertools import product 

C = 100 

def _sum(arr, a, b): 
    return sum(arr[i][j] for i, j in itertools.product(range(a, b), repeat=2)) 

answer = (_sum(a, 1, C) - _sum(b, 1, C)) * (C-1)**2 

не так красиво, так как мы итерация подматрицы, но все-таки быстро. Если вы хотите использовать numpy, нарезанная версия может быть написана немного более сжато:

import numpy as np 
A = np.array(a, np.int32) 
B = np.array(b, np.int32) 
answer = (np.sum(A[1:100, 1:100]) - np.sum(B[1:100, 1:100])) * 99**2 
+0

OP хочет пропустить ноль, и мы не знаем длины массивов. Вам нужно будет добавить некоторые '[1: 100]' срезы. – Kevin

+0

Конечно, я просто дал общий алгоритм, если у вас есть два массива 100x100, и вы не хотите пропускать 0. –

+0

Также мое решение O (n^2), а не O (n^4). Он работает более чем на 99^4 элемента, да, но если мы возьмем n = 99^2 (количество элементов в одном массиве), это квадратично, а не четвертично. – Kevin

Смежные вопросы