[{"data":1,"prerenderedAt":968},["ShallowReactive",2],{"blog-\u002Fblog\u002Fpython-itertools-explained":3},{"id":4,"title":5,"body":6,"description":955,"difficulty":956,"extension":957,"framework":958,"frameworkSlug":50,"meta":959,"navigation":78,"order":82,"path":960,"qaPath":961,"seo":962,"stem":963,"subtopic":20,"topic":964,"topicSlug":965,"updated":966,"__hash__":967},"blog\u002Fblog\u002Fpython-itertools-explained.md","Python itertools Explained — Lazy Iterators for Chaining, Grouping, and Combinatorics",{"type":7,"value":8,"toc":945},"minimark",[9,14,27,31,45,201,211,215,224,342,348,352,366,501,508,512,518,634,641,645,648,733,754,758,777,899,903,941],[10,11,13],"h2",{"id":12},"python-itertools-explained","Python itertools, explained",[15,16,17,21,22,26],"p",{},[18,19,20],"code",{},"itertools"," is a collection of fast, ",[23,24,25],"strong",{},"lazy"," iterator building blocks. Everything it\nreturns is an iterator that produces values on demand, so you can compose pipelines over\nhuge or infinite streams without ever building a list in memory. Here are the tools worth\nknowing by heart.",[10,28,30],{"id":29},"infinite-iterators","Infinite iterators",[15,32,33,36,37,40,41,44],{},[18,34,35],{},"count",", ",[18,38,39],{},"cycle",", and ",[18,42,43],{},"repeat"," generate endless streams. They're useful precisely because\nthey're lazy — pair them with something that stops the iteration.",[46,47,52],"pre",{"className":48,"code":49,"language":50,"meta":51,"style":51},"language-python shiki shiki-themes github-light github-dark","from itertools import count, cycle, islice\n\nids = count(start=100, step=10)          # 100, 110, 120, ...\nprint(next(ids), next(ids))              # 100 110\n\ncolors = cycle([\"red\", \"green\", \"blue\"]) # loops forever\nfirst_seven = list(islice(colors, 7))    # ['red','green','blue','red','green','blue','red']\n","python","",[18,53,54,73,80,119,142,147,178],{"__ignoreMap":51},[55,56,59,63,67,70],"span",{"class":57,"line":58},"line",1,[55,60,62],{"class":61},"szBVR","from",[55,64,66],{"class":65},"sVt8B"," itertools ",[55,68,69],{"class":61},"import",[55,71,72],{"class":65}," count, cycle, islice\n",[55,74,76],{"class":57,"line":75},2,[55,77,79],{"emptyLinePlaceholder":78},true,"\n",[55,81,83,86,89,92,96,98,102,104,107,109,112,115],{"class":57,"line":82},3,[55,84,85],{"class":65},"ids ",[55,87,88],{"class":61},"=",[55,90,91],{"class":65}," count(",[55,93,95],{"class":94},"s4XuR","start",[55,97,88],{"class":61},[55,99,101],{"class":100},"sj4cs","100",[55,103,36],{"class":65},[55,105,106],{"class":94},"step",[55,108,88],{"class":61},[55,110,111],{"class":100},"10",[55,113,114],{"class":65},")          ",[55,116,118],{"class":117},"sJ8bj","# 100, 110, 120, ...\n",[55,120,122,125,128,131,134,136,139],{"class":57,"line":121},4,[55,123,124],{"class":100},"print",[55,126,127],{"class":65},"(",[55,129,130],{"class":100},"next",[55,132,133],{"class":65},"(ids), ",[55,135,130],{"class":100},[55,137,138],{"class":65},"(ids))              ",[55,140,141],{"class":117},"# 100 110\n",[55,143,145],{"class":57,"line":144},5,[55,146,79],{"emptyLinePlaceholder":78},[55,148,150,153,155,158,162,164,167,169,172,175],{"class":57,"line":149},6,[55,151,152],{"class":65},"colors ",[55,154,88],{"class":61},[55,156,157],{"class":65}," cycle([",[55,159,161],{"class":160},"sZZnC","\"red\"",[55,163,36],{"class":65},[55,165,166],{"class":160},"\"green\"",[55,168,36],{"class":65},[55,170,171],{"class":160},"\"blue\"",[55,173,174],{"class":65},"]) ",[55,176,177],{"class":117},"# loops forever\n",[55,179,181,184,186,189,192,195,198],{"class":57,"line":180},7,[55,182,183],{"class":65},"first_seven ",[55,185,88],{"class":61},[55,187,188],{"class":100}," list",[55,190,191],{"class":65},"(islice(colors, ",[55,193,194],{"class":100},"7",[55,196,197],{"class":65},"))    ",[55,199,200],{"class":117},"# ['red','green','blue','red','green','blue','red']\n",[15,202,203,206,207,210],{},[18,204,205],{},"islice"," is the standard way to take a finite slice of an infinite (or lazy) iterator — you\ncan't use ",[18,208,209],{},"[:7]"," on an iterator.",[10,212,214],{"id":213},"combining-and-slicing-streams","Combining and slicing streams",[15,216,217,220,221,223],{},[18,218,219],{},"chain"," flattens several iterables into one sequence; ",[18,222,205],{}," slices lazily without\nmaterialising.",[46,225,227],{"className":48,"code":226,"language":50,"meta":51,"style":51},"from itertools import chain, islice\n\nmerged = chain([1, 2], [3, 4], [5])      # 1 2 3 4 5 lazily\nlist(merged)                              # [1, 2, 3, 4, 5]\n\nbig = range(1_000_000)\nwindow = list(islice(big, 10, 20))        # items 10..19, no giant list built\n",[18,228,229,240,244,284,295,299,317],{"__ignoreMap":51},[55,230,231,233,235,237],{"class":57,"line":58},[55,232,62],{"class":61},[55,234,66],{"class":65},[55,236,69],{"class":61},[55,238,239],{"class":65}," chain, islice\n",[55,241,242],{"class":57,"line":75},[55,243,79],{"emptyLinePlaceholder":78},[55,245,246,249,251,254,257,259,262,265,268,270,273,275,278,281],{"class":57,"line":82},[55,247,248],{"class":65},"merged ",[55,250,88],{"class":61},[55,252,253],{"class":65}," chain([",[55,255,256],{"class":100},"1",[55,258,36],{"class":65},[55,260,261],{"class":100},"2",[55,263,264],{"class":65},"], [",[55,266,267],{"class":100},"3",[55,269,36],{"class":65},[55,271,272],{"class":100},"4",[55,274,264],{"class":65},[55,276,277],{"class":100},"5",[55,279,280],{"class":65},"])      ",[55,282,283],{"class":117},"# 1 2 3 4 5 lazily\n",[55,285,286,289,292],{"class":57,"line":121},[55,287,288],{"class":100},"list",[55,290,291],{"class":65},"(merged)                              ",[55,293,294],{"class":117},"# [1, 2, 3, 4, 5]\n",[55,296,297],{"class":57,"line":144},[55,298,79],{"emptyLinePlaceholder":78},[55,300,301,304,306,309,311,314],{"class":57,"line":149},[55,302,303],{"class":65},"big ",[55,305,88],{"class":61},[55,307,308],{"class":100}," range",[55,310,127],{"class":65},[55,312,313],{"class":100},"1_000_000",[55,315,316],{"class":65},")\n",[55,318,319,322,324,326,329,331,333,336,339],{"class":57,"line":180},[55,320,321],{"class":65},"window ",[55,323,88],{"class":61},[55,325,188],{"class":100},[55,327,328],{"class":65},"(islice(big, ",[55,330,111],{"class":100},[55,332,36],{"class":65},[55,334,335],{"class":100},"20",[55,337,338],{"class":65},"))        ",[55,340,341],{"class":117},"# items 10..19, no giant list built\n",[15,343,344,347],{},[18,345,346],{},"chain.from_iterable(list_of_lists)"," is the idiomatic flatten when the iterables themselves\ncome from an iterable.",[10,349,351],{"id":350},"groupby-consecutive-runs","groupby — consecutive runs",[15,353,354,357,358,361,362,365],{},[18,355,356],{},"groupby"," collapses ",[23,359,360],{},"consecutive"," equal keys into groups. The catch that trips everyone\nup: it only groups adjacent items, so you almost always ",[23,363,364],{},"sort by the same key first",".",[46,367,369],{"className":48,"code":368,"language":50,"meta":51,"style":51},"from itertools import groupby\n\ndata = [(\"a\", 1), (\"a\", 2), (\"b\", 3), (\"a\", 4)]\ndata.sort(key=lambda x: x[0])             # sort first — groupby is adjacency-based\nfor key, group in groupby(data, key=lambda x: x[0]):\n    print(key, [v for _, v in group])     # a [1,2,4]  then  b [3]\n",[18,370,371,382,386,432,455,480],{"__ignoreMap":51},[55,372,373,375,377,379],{"class":57,"line":58},[55,374,62],{"class":61},[55,376,66],{"class":65},[55,378,69],{"class":61},[55,380,381],{"class":65}," groupby\n",[55,383,384],{"class":57,"line":75},[55,385,79],{"emptyLinePlaceholder":78},[55,387,388,391,393,396,399,401,403,406,408,410,412,414,417,419,421,423,425,427,429],{"class":57,"line":82},[55,389,390],{"class":65},"data ",[55,392,88],{"class":61},[55,394,395],{"class":65}," [(",[55,397,398],{"class":160},"\"a\"",[55,400,36],{"class":65},[55,402,256],{"class":100},[55,404,405],{"class":65},"), (",[55,407,398],{"class":160},[55,409,36],{"class":65},[55,411,261],{"class":100},[55,413,405],{"class":65},[55,415,416],{"class":160},"\"b\"",[55,418,36],{"class":65},[55,420,267],{"class":100},[55,422,405],{"class":65},[55,424,398],{"class":160},[55,426,36],{"class":65},[55,428,272],{"class":100},[55,430,431],{"class":65},")]\n",[55,433,434,437,440,443,446,449,452],{"class":57,"line":121},[55,435,436],{"class":65},"data.sort(",[55,438,439],{"class":94},"key",[55,441,442],{"class":61},"=lambda",[55,444,445],{"class":65}," x: x[",[55,447,448],{"class":100},"0",[55,450,451],{"class":65},"])             ",[55,453,454],{"class":117},"# sort first — groupby is adjacency-based\n",[55,456,457,460,463,466,469,471,473,475,477],{"class":57,"line":144},[55,458,459],{"class":61},"for",[55,461,462],{"class":65}," key, group ",[55,464,465],{"class":61},"in",[55,467,468],{"class":65}," groupby(data, ",[55,470,439],{"class":94},[55,472,442],{"class":61},[55,474,445],{"class":65},[55,476,448],{"class":100},[55,478,479],{"class":65},"]):\n",[55,481,482,485,488,490,493,495,498],{"class":57,"line":149},[55,483,484],{"class":100},"    print",[55,486,487],{"class":65},"(key, [v ",[55,489,459],{"class":61},[55,491,492],{"class":65}," _, v ",[55,494,465],{"class":61},[55,496,497],{"class":65}," group])     ",[55,499,500],{"class":117},"# a [1,2,4]  then  b [3]\n",[15,502,503,504,507],{},"Each ",[18,505,506],{},"group"," is itself a one-shot iterator — consume it before advancing to the next group.",[10,509,511],{"id":510},"accumulate-running-totals","accumulate — running totals",[15,513,514,517],{},[18,515,516],{},"accumulate"," yields a running reduction. By default it's a cumulative sum, but pass any\nbinary function.",[46,519,521],{"className":48,"code":520,"language":50,"meta":51,"style":51},"from itertools import accumulate\nimport operator\n\nlist(accumulate([1, 2, 3, 4]))                    # [1, 3, 6, 10]\nlist(accumulate([1, 2, 3, 4], operator.mul))      # [1, 2, 6, 24]\nlist(accumulate([3, 1, 4, 1, 5], max))            # [3, 3, 4, 4, 5] running max\n",[18,522,523,534,541,545,572,598],{"__ignoreMap":51},[55,524,525,527,529,531],{"class":57,"line":58},[55,526,62],{"class":61},[55,528,66],{"class":65},[55,530,69],{"class":61},[55,532,533],{"class":65}," accumulate\n",[55,535,536,538],{"class":57,"line":75},[55,537,69],{"class":61},[55,539,540],{"class":65}," operator\n",[55,542,543],{"class":57,"line":82},[55,544,79],{"emptyLinePlaceholder":78},[55,546,547,549,552,554,556,558,560,562,564,566,569],{"class":57,"line":121},[55,548,288],{"class":100},[55,550,551],{"class":65},"(accumulate([",[55,553,256],{"class":100},[55,555,36],{"class":65},[55,557,261],{"class":100},[55,559,36],{"class":65},[55,561,267],{"class":100},[55,563,36],{"class":65},[55,565,272],{"class":100},[55,567,568],{"class":65},"]))                    ",[55,570,571],{"class":117},"# [1, 3, 6, 10]\n",[55,573,574,576,578,580,582,584,586,588,590,592,595],{"class":57,"line":144},[55,575,288],{"class":100},[55,577,551],{"class":65},[55,579,256],{"class":100},[55,581,36],{"class":65},[55,583,261],{"class":100},[55,585,36],{"class":65},[55,587,267],{"class":100},[55,589,36],{"class":65},[55,591,272],{"class":100},[55,593,594],{"class":65},"], operator.mul))      ",[55,596,597],{"class":117},"# [1, 2, 6, 24]\n",[55,599,600,602,604,606,608,610,612,614,616,618,620,622,625,628,631],{"class":57,"line":149},[55,601,288],{"class":100},[55,603,551],{"class":65},[55,605,267],{"class":100},[55,607,36],{"class":65},[55,609,256],{"class":100},[55,611,36],{"class":65},[55,613,272],{"class":100},[55,615,36],{"class":65},[55,617,256],{"class":100},[55,619,36],{"class":65},[55,621,277],{"class":100},[55,623,624],{"class":65},"], ",[55,626,627],{"class":100},"max",[55,629,630],{"class":65},"))            ",[55,632,633],{"class":117},"# [3, 3, 4, 4, 5] running max\n",[15,635,636,637,640],{},"It's the lazy, streaming cousin of ",[18,638,639],{},"functools.reduce"," that keeps every intermediate result.",[10,642,644],{"id":643},"combinatorics-product-permutations-combinations","Combinatorics — product, permutations, combinations",[15,646,647],{},"These generate combinatoric sequences lazily, replacing hand-rolled nested loops.",[46,649,651],{"className":48,"code":650,"language":50,"meta":51,"style":51},"from itertools import product, permutations, combinations\n\nlist(product([0, 1], repeat=2))           # [(0,0),(0,1),(1,0),(1,1)] — nested loops\nlist(permutations(\"ABC\", 2))              # ordered pairs: AB AC BA BC CA CB\nlist(combinations(\"ABC\", 2))              # unordered pairs: AB AC BC\n",[18,652,653,664,668,695,715],{"__ignoreMap":51},[55,654,655,657,659,661],{"class":57,"line":58},[55,656,62],{"class":61},[55,658,66],{"class":65},[55,660,69],{"class":61},[55,662,663],{"class":65}," product, permutations, combinations\n",[55,665,666],{"class":57,"line":75},[55,667,79],{"emptyLinePlaceholder":78},[55,669,670,672,675,677,679,681,683,685,687,689,692],{"class":57,"line":82},[55,671,288],{"class":100},[55,673,674],{"class":65},"(product([",[55,676,448],{"class":100},[55,678,36],{"class":65},[55,680,256],{"class":100},[55,682,624],{"class":65},[55,684,43],{"class":94},[55,686,88],{"class":61},[55,688,261],{"class":100},[55,690,691],{"class":65},"))           ",[55,693,694],{"class":117},"# [(0,0),(0,1),(1,0),(1,1)] — nested loops\n",[55,696,697,699,702,705,707,709,712],{"class":57,"line":121},[55,698,288],{"class":100},[55,700,701],{"class":65},"(permutations(",[55,703,704],{"class":160},"\"ABC\"",[55,706,36],{"class":65},[55,708,261],{"class":100},[55,710,711],{"class":65},"))              ",[55,713,714],{"class":117},"# ordered pairs: AB AC BA BC CA CB\n",[55,716,717,719,722,724,726,728,730],{"class":57,"line":144},[55,718,288],{"class":100},[55,720,721],{"class":65},"(combinations(",[55,723,704],{"class":160},[55,725,36],{"class":65},[55,727,261],{"class":100},[55,729,711],{"class":65},[55,731,732],{"class":117},"# unordered pairs: AB AC BC\n",[15,734,735,738,739,741,742,745,746,749,750,753],{},[18,736,737],{},"product"," replaces nested ",[18,740,459],{}," loops; ",[18,743,744],{},"permutations"," cares about order; ",[18,747,748],{},"combinations","\ndoesn't. Add ",[18,751,752],{},"combinations_with_replacement"," when repeats are allowed.",[10,755,757],{"id":756},"filtering-and-pairing-helpers","Filtering and pairing helpers",[15,759,760,761,764,765,768,769,772,773,776],{},"A few more everyday tools: ",[18,762,763],{},"takewhile","\u002F",[18,766,767],{},"dropwhile"," for prefix-based filtering, ",[18,770,771],{},"pairwise","\n(3.10+) for sliding adjacent pairs, and ",[18,774,775],{},"starmap"," to unpack tuples into a function.",[46,778,780],{"className":48,"code":779,"language":50,"meta":51,"style":51},"from itertools import takewhile, pairwise, starmap\n\nlist(takewhile(lambda x: x \u003C 3, [1, 2, 3, 1]))   # [1, 2] — stops at first failure\nlist(pairwise([1, 2, 3, 4]))                      # [(1,2),(2,3),(3,4)]\nlist(starmap(pow, [(2, 3), (3, 2)]))              # [8, 9] — pow(2,3), pow(3,2)\n",[18,781,782,793,797,839,866],{"__ignoreMap":51},[55,783,784,786,788,790],{"class":57,"line":58},[55,785,62],{"class":61},[55,787,66],{"class":65},[55,789,69],{"class":61},[55,791,792],{"class":65}," takewhile, pairwise, starmap\n",[55,794,795],{"class":57,"line":75},[55,796,79],{"emptyLinePlaceholder":78},[55,798,799,801,804,807,810,813,816,819,821,823,825,827,829,831,833,836],{"class":57,"line":82},[55,800,288],{"class":100},[55,802,803],{"class":65},"(takewhile(",[55,805,806],{"class":61},"lambda",[55,808,809],{"class":65}," x: x ",[55,811,812],{"class":61},"\u003C",[55,814,815],{"class":100}," 3",[55,817,818],{"class":65},", [",[55,820,256],{"class":100},[55,822,36],{"class":65},[55,824,261],{"class":100},[55,826,36],{"class":65},[55,828,267],{"class":100},[55,830,36],{"class":65},[55,832,256],{"class":100},[55,834,835],{"class":65},"]))   ",[55,837,838],{"class":117},"# [1, 2] — stops at first failure\n",[55,840,841,843,846,848,850,852,854,856,858,860,863],{"class":57,"line":121},[55,842,288],{"class":100},[55,844,845],{"class":65},"(pairwise([",[55,847,256],{"class":100},[55,849,36],{"class":65},[55,851,261],{"class":100},[55,853,36],{"class":65},[55,855,267],{"class":100},[55,857,36],{"class":65},[55,859,272],{"class":100},[55,861,862],{"class":65},"]))                      ",[55,864,865],{"class":117},"# [(1,2),(2,3),(3,4)]\n",[55,867,868,870,873,876,879,881,883,885,887,889,891,893,896],{"class":57,"line":144},[55,869,288],{"class":100},[55,871,872],{"class":65},"(starmap(",[55,874,875],{"class":100},"pow",[55,877,878],{"class":65},", [(",[55,880,261],{"class":100},[55,882,36],{"class":65},[55,884,267],{"class":100},[55,886,405],{"class":65},[55,888,267],{"class":100},[55,890,36],{"class":65},[55,892,261],{"class":100},[55,894,895],{"class":65},")]))              ",[55,897,898],{"class":117},"# [8, 9] — pow(2,3), pow(3,2)\n",[10,900,902],{"id":901},"recap","Recap",[15,904,905,907,908,910,911,764,913,764,915,917,918,920,921,923,924,926,927,930,931,933,934,764,936,764,938,940],{},[18,906,20],{}," gives you ",[23,909,25],{}," iterator building blocks that compose into memory-efficient\npipelines: ",[18,912,35],{},[18,914,39],{},[18,916,43],{}," for infinite streams (bound them with ",[18,919,205],{},"),\n",[18,922,219],{}," to concatenate, ",[18,925,356],{}," for ",[928,929,360],"em",{}," runs (sort first!), ",[18,932,516],{}," for\nrunning reductions, and ",[18,935,737],{},[18,937,744],{},[18,939,748],{}," for combinatorics without\nnested loops. Because everything is an on-demand iterator, these tools scale to huge or\ninfinite data that would never fit in a list.",[942,943,944],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":51,"searchDepth":75,"depth":75,"links":946},[947,948,949,950,951,952,953,954],{"id":12,"depth":75,"text":13},{"id":29,"depth":75,"text":30},{"id":213,"depth":75,"text":214},{"id":350,"depth":75,"text":351},{"id":510,"depth":75,"text":511},{"id":643,"depth":75,"text":644},{"id":756,"depth":75,"text":757},{"id":901,"depth":75,"text":902},"A practical tour of Python's itertools — infinite iterators, chain, islice, groupby, accumulate, and the combinatoric tools product, permutations, and combinations, all lazy and memory-efficient.","medium","md","Python",{},"\u002Fblog\u002Fpython-itertools-explained","\u002Fpython\u002Ffunctional\u002Fitertools",{"title":5,"description":955},"blog\u002Fpython-itertools-explained","Functional Programming","functional","2026-06-19","xy9LGVo6rIqugwq3y9ls31BpypHZKvWiDC1KfrqW5ho",1782244093531]