화이트 파이썬 연구는 (구) itertools 심층 분석, 건조 제품의 전체를 (에) 노트

머리말

오늘 itertools 내 자신의 학습 경험을 공유하고, 파이썬은 기본적인 이해에 의해, 나는 그 크게 업무의 ​​효율성을 향상시킬 수 있습니다 발견, 매우 실용적인 방법의 다양성을 포함하는 라이브러리와 함께 제공 itertools.

itertools에 대한 첫 번째 세부 사항, 나는 공식 문서를 참조하는 파이썬 3.7 : itertools - 효율적인 루핑에 대한 반복자 기능 만들기 , 우리는 가서 볼 수 있습니다 관심이 더 중국어 버전이없는, 매우 유감으로, 하나를 Tucao 거기 있었다 , 한국어, 중국어 버전은 일본어 무엇을 유지하지 않습니다나요?

이야기 책 규칙, 내가 가장 멋진 일이라고 생각 Python3를 itertools!

당신이 그것을 들어하지 않은 경우, 당신은 가장 큰 숨겨진 보물 Python3 표준 라이브러리, 그래, 난 곧 포기 바로 공유 모음 모듈 중 하나 놓치고있어 : 파이썬 연구 노트 (칠) 마법의 보물 컬렉션의 흰색을 결국, 사람들은 큰 하위 속보입니다

itertools 기능 모듈을 학습 할 수 많은 훌륭한 온라인 리소스가 있습니다. 하지만 공식 문서가 항상 좋은 출발점이라고 생각합니다. 문서에서 대조에이 문서는 기본적으로 기반으로합니다.

itertools 기능이 포함 된 기능에 대해 단지 알고 학습 후 내 전반적인 느낌은 충분하다, 콘테스트가 없습니다. 진정한 힘은 생성이 기능의 조합에있다 , 빨리 매우 적은 메모리 효율성, 아름답고 우아한 소요 코드를.

시작하기 전에 상당히 과학 능력은 다음을 참조 수 무슨 내 친구 반복자 및 발전기 모르는 경우이 긴 기사에서는, 전체 사본을 향해 모든 세부 사항을 내 학습 과정의 종합적인 검토를 수행합니다 :

매직 itertools ##

꾸준한 도움이 앉아, 우리는 문서의 공식 정의에 따라, 기차에 준비가 있습니다 :

이 모듈은 APL, 하스켈과 SML의 구조에서 영감을 반복자 빌딩 블록의 숫자를 구현합니다. 각각은 파이썬에 적합한 형태로 개작되었다.

아마 반복자를 구축 모듈의 숫자의 실현 번역, 그들은, 등등 효율성을 향상시킬 수 있습니다 ...... APL, 하스켈과 SML 출신 건설하고 영감

이것은 주로 기능 itertools 반복자 "작업"에 더 복잡한 반복자를 생성한다는 것을 의미한다. 예를 들어, 매개 변수로서 반복 가능 객체의 번호 및 해당 튜플 요소 iterator를 내장 지퍼 () 함수를 고려해


print(list(zip([1, 2, 3], ['a', 'b', 'c'])))
Out:[(1, 'a'), (2, 'b'), (3, 'c')]

复制代码

작동 방식은 결국 압축?

다른 목록 [1,2,3] 및 [ 'A', 'B', 'C'] 마찬가지로 그들은 시간 요소를 반환 할 수 있다는 것을 의미하는 반복적이다. 기술적으로, 어떤 구현 :

  • .__ ITER의 __ ()

  • 또는 .__의 getItem의 __ ()

파이썬 객체 방법을 사용할 수 반복합니다. 이와 관련하여 질문 사항이있는 경우, 우리는 전문에 언급 된 튜토리얼을 볼 수 있습니다

객체 또는 다른 반복 X의 목록에서 호출 할 때, x는 자신의 반복자 객체로 돌아갑니다 ITER () 내장 함수 소개 :

iter([1, 2, 3, 4])  
iter((1,2,3,4))
iter({'a':1,'b':2})

Out:<list_iterator object at 0x00000229E1D6B940>
     <tuple_iterator object at 0x00000229E3879A90>
     <dict_keyiterator object at 0x00000229E1D6E818>
复制代码

실제로, 각 파라미터 ITER (호출하여 ZIP () 함수), 각각의 반복에 의해 반환 된 다음 () 추진 ITER () 및 달성 튜플 중합의 결과가 사용한다. 우편 () 반환 된 튜플을 반복을

그리고 난 당신이 기억해야 할에 전에, 쓰기, 흰색 파이썬 연구 노트가 (오)지도, 필터, 감소, 우편 요약 사실, 또한 반복자 작업의 무언가이다,지도 () 내장 함수를 소개 그것에는 단순한 하나의 인자 기능을 반복 시퀀스의 각 요소에 적용될 수있다 형성 분해 :

  • 틀 :지도 (FUNC, 순서)
list(map(len, ['xiaobai', 'at', 'paris']))
Out: [7, 2, 5]
复制代码

참고지도 템플릿은 찾기 어렵지 않다 :지도 () 함수를 순서 ()에 ITER를 호출하여 사용하는 다음 () 반복자가 소진 될 때까지이 반복자에 의해 반환되는 값을 촉진하고, FUNC 다음의 각 단계에 적용하기 (). 위의 예에서 iterator를 각 요소 LEN [ '에서'xiaobai ','파리 () 호출함으로써리스트의 각 요소의 길이

반복자 반복의 조합에 복수의 요소를 생성한다 () 및지도 () 반복기를 압축 할 수 있으므로 반복하고 있기 때문이다. 예를 들어, 두 개의 합 해당 요소들의리스트 다음 :

a = [1, 2, 3]
b = [4, 5, 6]
list(map(sum, zip(a,b)))

Out: [5, 7, 9]

复制代码

이 예는 소위 좋은 itertools 구축하는 방법을 설명 "반복자 대수를" 기능을 의미합니다. 우리는 건물의 벽돌의 세트가 합과 같은 경우처럼 특별한 "데이터 파이프"를 형성하기 위해 결합 될 수로 볼 itertools 수 있습니다.

사실, 파이썬 3에서, 경우에 우리는이 두 가지 기능이 반복자를 반환하기 때문에, 그것은, itertools을 사용하고있다지도 () 및 우편 ()를 사용!

우리는 이것이 소위 내부 itertools 사용 "반복자 대수학" 장점은 두 가지이다 :

  1. 메모리 효율 (게으른 평가) 개선
  2. 속도

질문이 두 친구에게 혜택이있을 수 있습니다, 우리는 특정 시나리오를 분석 할 수 있습니다, 걱정하지 마세요 :

이제 우리는 N의 길이의 함수로 그룹으로 목록 분할을 준비하기 위해, 목록과 양의 정수 n이있다. 단순화를 위해,리스트의 입력 길이 N에 의해 ​​나누어 질 수 있음을 가정한다. 예를 들어, 입력 경우 = [1,2,3,4,5,6]이고, n = 2, 함수 반환한다 [(1,2), (3,4), (5,6)].

우리는 먼저 다음과 같은 솔루션이 될 줄 알았는데 :

def naive_grouper(lst, n):
    num_groups = len(lst) // n
    return [tuple(lst[i*n:(i+1)*n]) for i in range(num_groups)]
复制代码

우리의 간단한 테스트 결과는 올바른 :

nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
naive_grouper(nums, 2)
Out: [(1, 2), (3, 4), (5, 6), (7, 8), (9, 10)]

复制代码

하지만 문제는 우리가 1 억 개 요소를 포함하는 목록을 통과하려고하면 무슨 일입니까? 우리는 많은 메모리를 필요로한다! 충분한 메모리를가하더라도 최종 결과가 생성 될 때까지 프로그램은 시간이 정지됩니다

우리는이 시간을 사용하는 경우 반복자 내부 itertools 크게 상황을 개선 할 수 있습니다 :

def better_grouper(lst, n):
    iters = [iter(lst)] * n
    return zip(*iters)
复制代码

이 방법은 우리가 지금보다 OPEN LOOK, 식 [iters (LST) * n은 N과 동일한 반복기에 대한 참조들의리스트를 생성, 많은 양의 정보가 조금 포함

nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
iters = [iter(nums)] * 2
list(id(itr) for itr in iters)    # Id 没有变化,就是创建了n个索引

Out: [1623329389256, 1623329389256]

复制代码

다음 반복기는 iters의 각 반복에 지퍼 (iters *)에 대응하는 요소를 반환한다. 상기 제 1 요소는 "시작"이터레이터 단지 기준이기 때문에, 지금 시작하므로 포워드하는 단계를 취하도록 "제"이터레이터 (2)로부터 "초"이터레이터에서 촬영하는 경우. 따라서, 지퍼 ()는 (1,2) 제 튜플은 생성한다.

이때, (우편 () (3)는 "초"를 생성하기 위해 상기 4 튜플에서 얻어진 반복기에 "첫 번째"로부터 인출 될 때, "2"이터레이터 3 시작 소위 iters 3, 4). 이 프로세스는 ZIP () 마지막 세대 (9, 10)으로 진행하고, "2"반복자 최대 사용 iters :

참고 : 여기에 "첫 번째", "초", "두"ID 때문에 변화, 반복자를 가리키는되지 않습니다! !

마지막으로, 우리는 결과가 동일 함을 찾을 수 있습니다 :

nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
list(better_grouper(nums, 2))

Out: [(1, 2), (3, 4), (5, 6), (7, 8), (9, 10)]
复制代码

그러나 여기 내가 테스트를했고, 두 개의 메모리 소비뿐만 아니라 nums에 넣어 빨리 500 개 이상의 시간을 수행 할 수있는 ITER 우편 () + 조합의 사용, 우리는 자신을 테스트 할 수 있습니다 관심에 큰 차이가 있음을 발견 범위 (100,000,000)에

지금은 그냥 작성 better_grouper (LST, n)의 방법을 찾기가 어렵지 않다 살펴 보자,이 방법의 명백한 단점이있다 : 우리가 LST 할 수없는 N로 나눠 길이를 전달하는 경우 실행될 때, 중요한 문제가 될 것입니다 :

>>> nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> list(better_grouper(nums, 4))
[(1, 2, 3, 4), (5, 6, 7, 8)]
复制代码

패킷 출력 요소 9 10 없음. 이것은 그것이 반복 최단 번호로 전달되면 배출되므로, 지퍼 () 요소 중합을 정지 발생한다. 그리고 우리는 어떤 요소가 누락되지 싶다. 그래서 해결책은 우리가 사용할 수 있다는 것입니다 itertools.zip_longest를 () 는 매개 변수의 반복 가능 객체의 수를 수용하고이 키워드를 fillvalue 수, 기본값은 없음입니다. 우리는 간단한 예를 살펴

>>> import itertools as it
>>> x = [1, 2, 3, 4, 5]
>>> y = ['a', 'b', 'c']

>>> list(zip(x, y))                     # zip总是执行完最短迭代次数停止
[(1, 'a'), (2, 'b'), (3, 'c')]

>>> list(it.zip_longest(x, y))          
[(1, 'a'), (2, 'b'), (3, 'c'), (4, None), (5, None)]

复制代码

이 예는 매우 명확하고 압축 ()와 zip_longest () 차이를 반영, 지금 우리는 better_grouper 방법을 최적화 할 수있다 :

import itertools as it


def grouper(lst, n, fillvalue=None):
    iters = [iter(lst)] * n
    return it.zip_longest(*iters, fillvalue=fillvalue)  #  默认就是None
    
复制代码

우리는 최적화 된 테스트를 보면 :

>>> nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> print(list(grouper(nums, 4)))
[(1, 2, 3, 4), (5, 6, 7, 8), (9, 10, None, None)]
复制代码

아주 좋은되었습니다, 그리고 학생들이 인식되지 않을 수 있습니다, 우리가 행한는 식용 방법 내부의 모든 전 과정의 itertools를 만드는 것입니다!

이제 진짜 살펴 보자 공식 문서 안에 기록 된 식용 방법 :

그리고 우리는 반복자는 * 인수를 사용하여 여러 매개 변수를 받아 들일 수 제외하고는 기본적으로 동일한 쓰기

마지막으로 만족 테스트 :

from itertools import zip_longest

def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return zip_longest(*args, fillvalue=fillvalue)
    
test_list = list(grouper("ABCDEFG",3))
test_tuple = tuple(grouper(range(0,7),2,'Null'))
test_dict = dict(zip(test_list,test_tuple))


复制代码

출력 :

print(test_list)
Out:[('A', 'B', 'C'), ('D', 'E', 'F'), ('G', None, None)]
复制代码
print(test_tuple)
Out:((0, 1), (2, 3), (4, 5), (6, 'Null'))
复制代码
print(test_dict)
Out: {('A', 'B', 'C'): (0, 1), ('D', 'E', 'F'): (2, 3), ('G', None, None): (4, 5)}
复制代码

폭력 해결 (무력)

첫째, 능력의 기본 개념은 간단 측면에서 소위 폭력을 해결하기위한 알고리즘이입니다 모든 상황을 열거 나 다른 방법을 사용하여 문제를 해결하기 위해, 컴퓨팅 기술의 여지가 없습니다. 나는 폭력 알고리즘의 광범위한 개념을 읽은 후, 첫 번째 생각은 실제로 왕 지방의 무덤이다

당신이 무덤 친구를 보았다면, 당신은 왕이 지방이 해결 발생하는 수많은 어려움에 자신의 위치를 ​​변경하는 폭력의 존경받는 사람이 실제로 발견 할 것이다 "열거 방법은"폭력을 해결하기 위해, 예를 들어, 나는 대부분의 감동 겐팅 사원이었다 의 "유령 주위에"직접 최종 솔루션에서, 모든 가능성을 규칙을 열거하여 당신이 벗어날 수 없다 보석, 왕 지방의 전체 옷장에 갇혀 보행자한다.

PS : 여기 남쪽 삼촌을 보내 경례, 그리고 구덩이에 기입하지 않는 사람들을 자신의

탈선은 다시 현실로, 우리는 종종 다음과 같은 고전적인 주제를 발생 :

당신은 세 $ 20 지폐 다섯 $ (10) 청구서,이 개 $ (5) 지폐와 다섯 $ (1) 청구서를 가지고있다. $ 100 얼마나 많은 다른 방법을 얻을 수 있나요?

이 문제를 무력하기 위해, 우리는 단지 조합의 모든 가능성의 목록을 넣어, 다음 $ (100) 조합은, 우선 될 수 있습니다 발견의 우리의 손에 모든 달러를 포함, 목록을 만들 수 있습니다 :

bills = [20, 20, 20, 10, 10, 10, 10, 10, 5, 5, 1, 1, 1, 1, 1]

复制代码

여기 itertools은 우리에게 도움이 될 것입니다. itertools.combinations ()는 두 개의 매개 변수를 사용할

  • 반복적 입력
  • 양의 정수 n

결국, N 요소의 모든 조합의 입력 요소 반복자를 생성한다.

import  itertools as it

bills = [20, 20, 20, 10, 10, 10, 10, 10, 5, 5, 1, 1, 1, 1, 1]

result =list(it.combinations(bills, 3))
print(len(result))  # 455种组合
print(result)

Out: 455
     [(20, 20, 20), (20, 20, 10), (20, 20, 10), ... ]
复制代码

내가 유일하게 남아있는 고등학교 수학이 C 15 (첨자)의 확률 내부에 실제로 나에게 말한다 오전 3 (첨자) 문제가 아니라, 지금 우리는 다양한 조합을, 그래서 우리는 다양한 조합으로 필요 선택된 동일한 (100)의 총 수의 문제가 해결된다 :

makes_100 = []
for n in range(1, len(bills) + 1):
    for combination in it.combinations(bills, n):
        if sum(combination) == 100:
            makes_100.append(combination)
复制代码

따라서 반복되는 조합을 포함 얻어진 결과는, 우리는 마침내 답을 얻을, 스트레이트 세트로 마지막에 중복 값을 필터링 할 수 있습니다 :

import  itertools as it

bills = [20, 20, 20, 10, 10, 10, 10, 10, 5, 5, 1, 1, 1, 1, 1]

makes_100 = []
for n in range(1, len(bills) + 1):
    for combination in it.combinations(bills, n):
        if sum(combination) == 100:
            makes_100.append(combination)

print(set(makes_100))

Out:{(20, 20, 10, 10, 10, 10, 10, 5, 1, 1, 1, 1, 1),
      (20, 20, 10, 10, 10, 10, 10, 5, 5),
     (20, 20, 20, 10, 10, 10, 5, 1, 1, 1, 1, 1),
     (20, 20, 20, 10, 10, 10, 5, 5),
     (20, 20, 20, 10, 10, 10, 10)}
     
复制代码

그래서 결국 우리는 다섯 가지 방법의 총을 발견했다. 이제 질문은 질문하는 항목을 변경할 수 있습니다, 그것은 완전히 다른 것입니다 :

이제 변화에 $ 100 법안을, 당신은 $ 20 $ 10 $ 5, $ (1) 청구서, 얼마나 많은 방법에 $ 50 숫자를 사용할 수 있습니까?

이 경우, 우리는 지폐의 일정량이없는, 그래서 우리는 가능한 모든 조합의 수를 사용하여 청구서를 생성하는 방법이 필요합니다. 이를 위해, 우리는 ** itertools.combinations_with_replacement () ** 기능을 사용해야합니다.

그것은 입력 받아 입력 및 반복 N 양의 정수로서 같은 조합 ()이고, 상기 n 튜플로부터 입력 반복자를 반환한다. 그 combination_with_replacement ()을 제외한 작은 밤나무 볼 튜플을 반환 반복 된 요소를 허용 :

>>> list(it.combinations_with_replacement([1, 2], 2))   #自己和自己的组合也可以
[(1, 1), (1, 2), (2, 2)]

复制代码

() itertools.combinations 대조 :

>>> list(it.combinations([1, 2], 2))   #不允许自己和自己的组合
[(1, 2)]
复制代码

새로운 문제, 다음과 같은 솔루션 그래서 :

bills = [50, 20, 10, 5, 1]
make_100 = []
for n in range(1, 101):
    for combination in it.combinations_with_replacement(bills, n):
        if sum(combination) == 100:
            makes_100.append(combination)
复制代码

이 방법은 조합에서 반복되지 않기 때문에 최종 결과는 우리가 무거운 갈 필요가 없습니다 :

>>> len(makes_100)
343
复制代码

당신이 스스로를 실행하는 경우, 그 출력은 시간이 좀 걸릴 것 알 수 있습니다. 이 96,560,645 조합을 처리해야하기 때문이다! 여기에서 우리는 해결하기 폭력의 구현에있다

또 "폭력"기능은 하나의 반복 가능를 받아 (재 배열)에 배치되어있는 모든 요소를 ​​생성 itertools 순열 ()이다 :

>>> list(it.permutations(['a', 'b', 'c']))
[('a', 'b', 'c'), ('a', 'c', 'b'), ('b', 'a', 'c'),
 ('b', 'c', 'a'), ('c', 'a', 'b'), ('c', 'b', 'a')]
复制代码

(예 : 목록으로) 반복자의 세 가지 요소의 모든 여섯 배치해야합니다, 긴 반복 배열 개체의 수는 매우 빠르게 성장한다. 사실, 반복 가능 객체의 길이, n은 n은! 배열 :

조합 (), combinations_with_replacement ()과 순열의 사용에 조합 폭발로 알려진 입력 현상 많은 양의 단 몇 결과는 () 우리는이 점을 명심해야합니다.

솔직히 말해서, 알고리즘은 폭력을 방지하는 것이 가장 좋습니다,하지만 때로는 우리가 사용 할 수 있습니다 (예 : 알고리즘의 필수 정확성으로, 또는 모든 가능한 결과를 고려해야합니다)

개요

제한된 공간으로 인해, 나는이 문서에서 우리는 다음과 같은 기능의 기본 원칙을 중심으로 심도있는 이해하고, 여기에 공유합니다 :

  • 지도()
  • 지퍼()
  • itertools.combinations
  • itertools.combinations_with_replacement
  • itertools.permutations

다음 글에서는 먼저 마지막 세를 요약 한 다음 itertools 내부 마법의 모든 종류의 것들을 공유 할 것

HTTPS : //juejin.im/post/5d075227f265da1bad570620 재현

추천

출처blog.csdn.net/weixin_33696106/article/details/93182267