{"id":2482,"date":"2026-02-02T07:48:45","date_gmt":"2026-02-02T07:48:45","guid":{"rendered":"https:\/\/demo.materiamedica.net\/demo6\/?p=2482"},"modified":"2026-02-02T07:48:56","modified_gmt":"2026-02-02T07:48:56","slug":"chapter-12-numpy-array-iterating","status":"publish","type":"post","link":"https:\/\/demo.materiamedica.net\/demo6\/chapter-12-numpy-array-iterating\/","title":{"rendered":"Chapter 12: NumPy Array Iterating"},"content":{"rendered":"<p dir=\"auto\"><strong>NumPy Array Iterating<\/strong> \u2014 written as if a patient teacher is sitting next to you, explaining slowly, showing many realistic examples, pointing out traps, comparing different methods, and telling you which one you should actually use in real life.<\/p>\n<p dir=\"auto\">Let\u2019s go step by step.<\/p>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Python<\/div>\n<div>\n<pre tabindex=\"0\"><code>import numpy as np<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<h3 dir=\"auto\">1. Why is iterating in NumPy different from normal Python?<\/h3>\n<p dir=\"auto\">In normal Python, we almost always iterate over lists with for loops:<\/p>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Python<\/div>\n<div>\n<pre tabindex=\"0\"><code>lst = [10, 20, 30, 40]\r\nfor x in lst:\r\n    print(x * 2)<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p dir=\"auto\">In NumPy \u2192 <strong>you should avoid simple Python for-loops whenever possible<\/strong> \u2192 because they are <strong>very slow<\/strong> compared to vectorized operations.<\/p>\n<p dir=\"auto\"><strong>Golden rule (write this down):<\/strong><\/p>\n<blockquote dir=\"auto\">\n<p dir=\"auto\">If you are using a Python for loop to do math on every element of a NumPy array \u2192 you are almost certainly doing it wrong<\/p>\n<\/blockquote>\n<p dir=\"auto\">But\u2026 sometimes you <strong>do<\/strong> need to iterate. So NumPy gives you several ways \u2014 some good, some acceptable, some <strong>very bad<\/strong>.<\/p>\n<h3 dir=\"auto\">2. The five main ways to iterate over NumPy arrays<\/h3>\n<p dir=\"auto\">Let\u2019s look at them from <strong>worst<\/strong> to <strong>best<\/strong> (in terms of when you should use them).<\/p>\n<h4 dir=\"auto\">Method 1 \u2013 Plain Python for loop (usually the worst choice)<\/h4>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Python<\/div>\n<div>\n<pre tabindex=\"0\"><code>arr = np.array([10, 20, 30, 40, 50])\r\n\r\n# Very slow &amp; not NumPy style\r\nfor x in arr:\r\n    print(x ** 2)<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p dir=\"auto\"><strong>When is this acceptable?<\/strong> Only when:<\/p>\n<ul dir=\"auto\">\n<li>The array is very small (&lt; 100 elements)<\/li>\n<li>You are doing something complicated that cannot be vectorized<\/li>\n<li>You are printing\/debugging<\/li>\n<\/ul>\n<p dir=\"auto\"><strong>Never<\/strong> do math like this on large arrays.<\/p>\n<h4 dir=\"auto\">Method 2 \u2013 Using .flat (iterates over all elements as 1D)<\/h4>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Python<\/div>\n<div>\n<pre tabindex=\"0\"><code>mat = np.array([[1, 2, 3],\r\n                [4, 5, 6],\r\n                [7, 8, 9]])\r\n\r\nfor x in mat.flat:\r\n    print(x, end=' ')           # 1 2 3 4 5 6 7 8 9<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p dir=\"auto\">\u2192 .flat gives you a <strong>1D iterator<\/strong> over <strong>all elements<\/strong>, no matter the shape.<\/p>\n<p dir=\"auto\"><strong>Use case example<\/strong> \u2014 very simple element inspection:<\/p>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Python<\/div>\n<div>\n<pre tabindex=\"0\"><code>for val in big_array.flat:\r\n    if val &lt; 0:\r\n        print(\"Found negative value!\")<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p dir=\"auto\">Still slow for large arrays \u2014 but better than nested loops.<\/p>\n<h4 dir=\"auto\">Method 3 \u2013 np.nditer \u2013 the most flexible (and most misunderstood) iterator<\/h4>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Python<\/div>\n<div>\n<pre tabindex=\"0\"><code>arr = np.array([[10, 20, 30],\r\n                [40, 50, 60]])\r\n\r\nit = np.nditer(arr)\r\n\r\nfor x in it:\r\n    print(x, end=' ')          # 10 20 30 40 50 60<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p dir=\"auto\"><strong>Important modes \/ flags<\/strong> \u2014 this is where nditer becomes powerful<\/p>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Python<\/div>\n<div>\n<pre tabindex=\"0\"><code># Read-only (default)\r\nfor x in np.nditer(arr):\r\n    print(x)\r\n\r\n# Read and write (very useful!)\r\nfor x in np.nditer(arr, op_flags=['readwrite']):\r\n    x[...] = x * 2              # modifies the original array!\r\n\r\nprint(arr)\r\n# [[ 20  40  60]\r\n#  [ 80 100 120]]<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p dir=\"auto\"><strong>Common realistic use case \u2013 modify array in place with condition<\/strong><\/p>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Python<\/div>\n<div>\n<pre tabindex=\"0\"><code>data = np.random.randint(-50, 50, (5, 6))\r\n\r\nfor x in np.nditer(data, op_flags=['readwrite']):\r\n    if x &lt; 0:\r\n        x[...] = 0\r\n\r\nprint(data)     # all negative values replaced with 0<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p dir=\"auto\"><strong>Flags cheat sheet<\/strong> (most useful ones)<\/p>\n<div>\n<div dir=\"auto\">\n<table dir=\"auto\">\n<thead>\n<tr>\n<th data-col-size=\"md\">Flag<\/th>\n<th data-col-size=\"lg\">Meaning<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td data-col-size=\"md\">readwrite<\/td>\n<td data-col-size=\"lg\">allow reading and writing<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"md\">readonly<\/td>\n<td data-col-size=\"lg\">default \u2013 cannot modify<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"md\">writeonly<\/td>\n<td data-col-size=\"lg\">only writing (rare)<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"md\">buffered<\/td>\n<td data-col-size=\"lg\">better performance for some operations<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"md\">common_dtype<\/td>\n<td data-col-size=\"lg\">force same dtype for all operands<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div><\/div>\n<\/div>\n<\/div>\n<h4 dir=\"auto\">Method 4 \u2013 np.ndenumerate \u2013 when you need both index and value<\/h4>\n<p dir=\"auto\">Very useful when you need to know <strong>where<\/strong> you are in the array.<\/p>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Python<\/div>\n<div>\n<pre tabindex=\"0\"><code>mat = np.array([[10, 20, 30],\r\n                [40, 50, 60],\r\n                [70, 80, 90]])\r\n\r\nfor index, value in np.ndenumerate(mat):\r\n    print(f\"Position {index} \u2192 value {value}\")<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p dir=\"auto\">Output:<\/p>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>text<\/div>\n<div>\n<pre tabindex=\"0\"><code>Position (0, 0) \u2192 value 10\r\nPosition (0, 1) \u2192 value 20\r\n...\r\nPosition (2, 2) \u2192 value 90<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p dir=\"auto\"><strong>Realistic use case<\/strong> \u2014 replace values based on position<\/p>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Python<\/div>\n<div>\n<pre tabindex=\"0\"><code>grid = np.zeros((5, 5))\r\n\r\nfor idx, _ in np.ndenumerate(grid):\r\n    row, col = idx\r\n    if row == col:\r\n        grid[idx] = 1           # put 1 on diagonal\r\n\r\nprint(grid)\r\n# [[1. 0. 0. 0. 0.]\r\n#  [0. 1. 0. 0. 0.]\r\n#  [0. 0. 1. 0. 0.]\r\n#  [0. 0. 0. 1. 0.]\r\n#  [0. 0. 0. 0. 1.]]<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<h4 dir=\"auto\">Method 5 \u2013 Vectorized operations \u2013 the NumPy way (best in 95% of cases)<\/h4>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Python<\/div>\n<div>\n<pre tabindex=\"0\"><code>arr = np.arange(1, 11)\r\n\r\n# DON'T do this:\r\n# for i in range(len(arr)):\r\n#     arr[i] = arr[i] ** 2\r\n\r\n# DO this:\r\narr = arr ** 2\r\nprint(arr)\r\n# [  1   4   9  16  25  36  49  64  81 100]<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p dir=\"auto\"><strong>Even with conditions:<\/strong><\/p>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Python<\/div>\n<div>\n<pre tabindex=\"0\"><code>values = np.random.randn(1000)\r\n\r\n# Slow and bad:\r\n# for i in range(len(values)):\r\n#     if values[i] &lt; 0:\r\n#         values[i] = 0\r\n\r\n# Fast and correct:\r\nvalues[values &lt; 0] = 0<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p dir=\"auto\"><strong>With multiple arrays:<\/strong><\/p>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>Python<\/div>\n<div>\n<pre tabindex=\"0\"><code>a = np.array([1, 2, 3, 4])\r\nb = np.array([10, 20, 30, 40])\r\n\r\n# DON'T:\r\n# result = []\r\n# for x, y in zip(a, b):\r\n#     result.append(x + y * 2)\r\n\r\n# DO:\r\nresult = a + b * 2<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<h3 dir=\"auto\">Summary \u2013 Which iteration method should you use?<\/h3>\n<div>\n<div dir=\"auto\">\n<table dir=\"auto\">\n<thead>\n<tr>\n<th data-col-size=\"lg\">Situation<\/th>\n<th data-col-size=\"md\">Recommended method<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td data-col-size=\"lg\">Doing math \/ logical operations on elements<\/td>\n<td data-col-size=\"md\"><strong>Vectorized operations<\/strong> (best)<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"lg\">Need index <strong>and<\/strong> value<\/td>\n<td data-col-size=\"md\">np.ndenumerate(&#8230;)<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"lg\">Need to modify array in place with complex logic<\/td>\n<td data-col-size=\"md\">np.nditer(&#8230;, op_flags=[&#8216;readwrite&#8217;])<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"lg\">Just want to look at \/ count \/ print all values<\/td>\n<td data-col-size=\"md\">.flat or nditer (read-only)<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"lg\">Array is tiny (&lt; 100 elements) &amp; logic is weird<\/td>\n<td data-col-size=\"md\">plain Python for is acceptable<\/td>\n<\/tr>\n<tr>\n<td data-col-size=\"lg\">You are doing serious data processing<\/td>\n<td data-col-size=\"md\"><strong>avoid loops<\/strong> \u2014 use vectorization, ufuncs, masking<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div><\/div>\n<\/div>\n<\/div>\n<h3 dir=\"auto\">Quick Decision Flowchart<\/h3>\n<ol dir=\"auto\">\n<li>Can I write this with vectorized operations (+, *, **, np.where, boolean indexing, etc.)? \u2192 Yes \u2192 <strong>do it<\/strong> (fastest, cleanest)<\/li>\n<li>Do I need both value and position (index)? \u2192 Yes \u2192 np.ndenumerate<\/li>\n<li>Do I need to modify the array in place with somewhat complex logic? \u2192 Yes \u2192 np.nditer with readwrite<\/li>\n<li>Do I just want to inspect\/read every element? \u2192 Yes \u2192 .flat or simple nditer<\/li>\n<li>Everything else \/ very small array? \u2192 plain Python for loop<\/li>\n<\/ol>\n<p dir=\"auto\">Would you like to go deeper into any of these?<\/p>\n<ul dir=\"auto\">\n<li>More realistic examples with np.nditer flags<\/li>\n<li>How to iterate over multiple arrays at once (broadcast_arrays)<\/li>\n<li>Speed comparison (vectorized vs loops)<\/li>\n<li>Common bugs when using nditer for writing<\/li>\n<li>Mini-exercise: clean\/modify an array using different methods<\/li>\n<\/ul>\n<p dir=\"auto\">Just tell me what feels most useful right now! \ud83d\ude0a<\/p>\n","protected":false},"excerpt":{"rendered":"<p>NumPy Array Iterating \u2014 written as if a patient teacher is sitting next to you, explaining slowly, showing many realistic examples, pointing out traps, comparing different methods, and telling you which one you should&#46;&#46;&#46;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[75],"tags":[],"class_list":["post-2482","post","type-post","status-publish","format-standard","hentry","category-numpy"],"_links":{"self":[{"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/posts\/2482","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/comments?post=2482"}],"version-history":[{"count":1,"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/posts\/2482\/revisions"}],"predecessor-version":[{"id":2483,"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/posts\/2482\/revisions\/2483"}],"wp:attachment":[{"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/media?parent=2482"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/categories?post=2482"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/tags?post=2482"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}