`suất` trong một thủ tục đệ quy


8

Giả sử tôi có một danh sách Python biểu thị các phạm vi cho một số biến:

conditions = [['i', (1, 5)], ['j', (1, 2)]]

Điều này thể hiện rằng iphạm vi biến từ 1 đến 5 và bên trong biến vòng lặp đó jnằm trong khoảng từ 1 đến 2. Tôi muốn có một từ điển cho mỗi kết hợp có thể:

{'i': 1, 'j': 1}
{'i': 1, 'j': 2}
{'i': 2, 'j': 1}
{'i': 2, 'j': 2}
{'i': 3, 'j': 1}
{'i': 3, 'j': 2}
{'i': 4, 'j': 1}
{'i': 4, 'j': 2}
{'i': 5, 'j': 1}
{'i': 5, 'j': 2}

Lý do là tôi muốn lặp đi lặp lại chúng. Nhưng vì toàn bộ không gian quá lớn, tôi không muốn tạo ra tất cả chúng, lưu trữ chúng và sau đó lặp lại danh sách từ điển đó. Tôi đã nghĩ về việc sử dụng thủ tục đệ quy sau đây, nhưng tôi cần một số trợ giúp với yieldphần này. Nó nên ở đâu? Làm thế nào để tôi tránh máy phát điện lồng nhau?

def iteration(conditions, currentCondition, valuedIndices):
    if currentCondition == len(conditions):
        yield valuedIndices
    else:
        cond = conditions[currentCondition]
        index = cond[0]
        lim1 = cond[1][0]
        lim2 = cond[1][1]
        for ix in range(lim1, lim2 + 1):
            valuedIndices[index] = ix
            yield iteration(conditions, currentCondition + 1, valuedIndices)

Bây giờ tôi muốn có thể làm:

for valued_indices in iteration(conditions, 0, {}):
    ...

3
Đơn giản chỉ cần thay thế yieldbằng yield fromtrong dòng cuối cùng của chức năng của bạn.
jfaccioni

Câu trả lời:


5

Đây là một trường hợp có thể dễ dàng lùi lại một bước và bắt đầu mới.

Hãy bắt đầu bằng cách tách các khóa và các khoảng cách riêng biệt, bằng cách sử dụng một thủ thuật nổi tiếng liên quan đến zip:

>>> keys, intervals = list(zip(*conditions))
>>> keys
('i', 'j')
>>> intervals
((1, 5), (1, 2))

(Sự tương ứng giữa hai lần duy trì ghép nối ban đầu; intervals[i]là khoảng cho biến keys[i]cho tất cả i.)

Bây giờ, hãy tạo các đối tượng phạm vi thích hợp từ các khoảng đó

>>> intervals = [range(x, y+1) for x, y in intervals]
>>> list(intervals[0])
[1, 2, 3, 4, 5]
>>> list(intervals[1])
[1, 2]

Chúng ta có thể tính toán sản phẩm của những rangeđối tượng này

>>> for v in product(*intervals):
...   print(v)
...
(1, 1)
(1, 2)
(2, 1)
(2, 2)
(3, 1)
(3, 2)
(4, 1)
(4, 2)
(5, 1)
(5, 2)

mà bạn nên nhận ra là các giá trị để sử dụng cho mỗi dict. Bạn có thể nén từng giá trị đó bằng các phím để tạo một bộ đối số thích hợp cho dictlệnh. Ví dụ:

>>> dict(zip(keys, (1,1)))
{'i': 1, 'j': 1}

Đặt tất cả những thứ này lại với nhau, chúng ta có thể lặp lại sản phẩm để dictlần lượt sản xuất , mang lại sản phẩm.

def iteration(conditions):
    keys, intervals = zip(*conditions)
    intervals = [range(x, y+1) for x, y in intervals]
    yield from (dict(zip(keys, v)) for v in product(*intervals))

0

Có lẽ bạn có thể đơn giản hóa một chút với sự hiểu biết về trình tạo nội bộ và yield fromnó:

def dict_factory(i, j):
    r1 = range(1, i + 1)
    r2 = range(1, j + 1)
    dictgen = ({'i':x, 'j':y} for x in r1 for y in r2)
    yield from dictgen

sử dụng như là:

foo = dict_factory(5, 2)
while True:
    print(next(foo))

Các điều kiện đưa ra được thông qua dưới dạng danh sách các danh sách tôi nghi ngờ OP cần một giải pháp hoạt động cho N số điều kiện không được mã hóa thành 2
Chris Doyle

@Chris Doyle điểm tốt, chức năng có lẽ nên được cấu trúc như dict_factory(*args)sau đó ... Hmmm ...
neutrino_logic

0

Tôi không chắc bạn có đặc biệt cần sử dụng đệ quy hay không nhưng bạn có thể tạo chúng bằng phương pháp sản phẩm itertools để tạo tất cả các kết hợp. Điều này được viết ở chỗ bạn có thể có 1 đến n điều kiện và nó vẫn hoạt động và trả lại cho bạn từng mục.

from itertools import product


def iterations2(conditions):
    labels, ranges = list(zip(*conditions))
    ranges = [range(item[0], item[1] + 1) for item in ranges]
    for nums in product(*ranges):
        yield dict(zip(labels, nums))


conditions = [['i', (1, 5)], ['j', (1, 2)], ['z', (3, 6)]]
for valued_indices in iterations2(conditions):
    print(valued_indices)

ĐẦU RA

{'i': 1, 'j': 1, 'z': 3}
{'i': 1, 'j': 1, 'z': 4}
{'i': 1, 'j': 1, 'z': 5}
{'i': 1, 'j': 1, 'z': 6}
{'i': 1, 'j': 2, 'z': 3}
{'i': 1, 'j': 2, 'z': 4}
{'i': 1, 'j': 2, 'z': 5}
{'i': 1, 'j': 2, 'z': 6}
{'i': 2, 'j': 1, 'z': 3}
{'i': 2, 'j': 1, 'z': 4}
{'i': 2, 'j': 1, 'z': 5}
{'i': 2, 'j': 1, 'z': 6}
{'i': 2, 'j': 2, 'z': 3}
{'i': 2, 'j': 2, 'z': 4}
{'i': 2, 'j': 2, 'z': 5}
{'i': 2, 'j': 2, 'z': 6}
{'i': 3, 'j': 1, 'z': 3}
{'i': 3, 'j': 1, 'z': 4}
{'i': 3, 'j': 1, 'z': 5}
{'i': 3, 'j': 1, 'z': 6}
{'i': 3, 'j': 2, 'z': 3}
{'i': 3, 'j': 2, 'z': 4}
{'i': 3, 'j': 2, 'z': 5}
{'i': 3, 'j': 2, 'z': 6}
{'i': 4, 'j': 1, 'z': 3}
{'i': 4, 'j': 1, 'z': 4}
{'i': 4, 'j': 1, 'z': 5}
{'i': 4, 'j': 1, 'z': 6}
{'i': 4, 'j': 2, 'z': 3}
{'i': 4, 'j': 2, 'z': 4}
{'i': 4, 'j': 2, 'z': 5}
{'i': 4, 'j': 2, 'z': 6}
{'i': 5, 'j': 1, 'z': 3}
{'i': 5, 'j': 1, 'z': 4}
{'i': 5, 'j': 1, 'z': 5}
{'i': 5, 'j': 1, 'z': 6}
{'i': 5, 'j': 2, 'z': 3}
{'i': 5, 'j': 2, 'z': 4}
{'i': 5, 'j': 2, 'z': 5}
{'i': 5, 'j': 2, 'z': 6}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.