{"id":460,"date":"2022-06-12T06:35:23","date_gmt":"2022-06-12T05:35:23","guid":{"rendered":"https:\/\/blog.univ-angers.fr\/mathsinfo\/?p=460"},"modified":"2022-06-19T08:03:20","modified_gmt":"2022-06-19T07:03:20","slug":"kata11","status":"publish","type":"post","link":"https:\/\/blog.univ-angers.fr\/mathsinfo\/2022\/06\/12\/kata11\/","title":{"rendered":"Onzi\u00e8me exercice en Python, JavaScript et APL"},"content":{"rendered":"\n<figure class=\"wp-block-image size-full is-resized\"><a href=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/06\/image-11.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/06\/image-11.png\" alt=\"\" class=\"wp-image-461\" width=\"315\" height=\"566\" \/><\/a><\/figure>\n\n\n\n<p><span style=\"text-decoration: underline\">R\u00e9sum\u00e9 en fran\u00e7ais<\/span> : On vous donne une <strong>matrice carr\u00e9e<\/strong> et un <strong>nombre<\/strong> <strong>n<\/strong>, vous devez renvoyer cette matrice dont les tous les termes ont \u00e9t\u00e9 tourn\u00e9s (<strong>n<\/strong> rotations) dans le sens <strong>anti-horaire<\/strong>. <span style=\"text-decoration: underline\">Exemple avec une matrice 3 x 3<\/span> :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>      Matrice initiale\n1 2 3\n4 5 6\n7 8 9\n      n = 1 rotation anti-horaire\n3 6 9\n2 5 8\n1 4 7\n      n = 2 rotations anti-horaire\n9 8 7\n6 5 4\n3 2 1\n      n = 3 rotations anti-horaire\n7 4 1\n8 5 2\n9 6 3<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Python : Facile avec une biblioth\u00e8que<\/h2>\n\n\n\n<p>La m\u00e9thode <strong>rot90<\/strong> de la biblioth\u00e8que <strong>Python<\/strong> <strong>numpy<\/strong> permet d&rsquo;effectuer des rotations de tableaux :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&gt;&gt; import numpy as np\n\n&gt;&gt; np.rot90(&#091;&#091;1, 2], &#091;3, 4]], 1)         # 1 rotation anti-horaire\narray(&#091;&#091;2, 4],\n       &#091;1, 3]])\n\n&gt;&gt; np.rot90(&#091;&#091;1, 2, 3], &#091;4, 5, 6]], 2)   # 2 rotations, matrice 2 x 3\narray(&#091;&#091;6, 5, 4],\n       &#091;3, 2, 1]])<\/code><\/pre>\n\n\n\n<p>Remarquons que 2 rotations <strong>n<sub>1<\/sub><\/strong> et <strong>n<sub>2<\/sub><\/strong> sont <strong>\u00e9quivalentes<\/strong> si la diff\u00e9rence <strong>n<sub>1<\/sub> &#8211; n<sub>2<\/sub><\/strong> est un <strong>multiple de 4<\/strong>. Par exemple, effectuer <strong>1<\/strong> rotation anti-horaire est \u00e9quivalent \u00e0 faire <strong>5<\/strong> rotations anti-horaires.<\/p>\n\n\n\n<p>De fa\u00e7on plus g\u00e9n\u00e9rale, <strong>n<\/strong> rotations anti-horaires sont \u00e9quivalentes \u00e0 <strong>n % 4<\/strong> rotations anti-horaires. D&rsquo;o\u00f9 cette version finale en Python :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import numpy as np\n\ndef rotation(matrice, n):\n    return np.rot90(matrice, n % 4).tolist()\n\n&gt;&gt; rotation(&#091;&#091;1, 2], &#091;4, 5]], 2)\n&#091;&#091;5, 4], &#091;2, 1]]<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">JavaScript &amp; APL : Effort moyen avec renversements et transpos\u00e9e<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Renversements et transpos\u00e9e<\/h3>\n\n\n\n<p>Le <strong>diagramme<\/strong> ci-dessous montre que l&rsquo;on peut obtenir une rotation anti-horaire <strong>\u21ba<\/strong> \u00e0 l&rsquo;aide de <strong>\u2349<\/strong> (<strong>transpos\u00e9e<\/strong>) et \u2296 (<strong>renversement<\/strong> vertical) ou de <strong>\u2349 et \u233d<\/strong> (<strong>renversement<\/strong> horizontal) :<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/06\/image-13.png\"><img loading=\"lazy\" decoding=\"async\" width=\"271\" height=\"271\" src=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/06\/image-13.png\" alt=\"\" class=\"wp-image-465\" srcset=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/06\/image-13.png 271w, https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/06\/image-13-150x150.png 150w\" sizes=\"auto, (max-width: 271px) 100vw, 271px\" \/><\/a><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">APL<\/h3>\n\n\n\n<p>APL dispose de plusieurs <strong>primitives<\/strong> pour effectuer des <strong>renversements<\/strong> et <strong>transpos\u00e9e<\/strong> :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>      m \u2190 2 2 \u2374 \u23734         \u235d Matrice 2 x 2\n      m\n1 2\n3 4\n      \u233d m                   \u235d renversement horizontal\n2 1\n4 3\n      \u2296 m                   \u235d renversement vertical\n3 4\n1 2\n      \u2349 m                   \u235d transpos\u00e9e\n1 3\n2 4<\/code><\/pre>\n\n\n\n<p>V\u00e9rifions : <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>      m \u2190 3 3 \u2374 \u23739\n      m\n1 2 3\n4 5 6\n7 8 9\n      (\u2296\u2349) m\n3 6 9\n2 5 8\n1 4 7\n      (\u2349\u233d) m\n3 6 9\n2 5 8\n1 4 7<\/code><\/pre>\n\n\n\n<p>Nous avons vu dans l&rsquo;exercice n\u00b09 que \u2363 permet de&nbsp;<strong>r\u00e9p\u00e9ter<\/strong>&nbsp;une op\u00e9ration plusieurs fois, par exemple pour 4 rotations anti-horaires (ce qui redonnera bien s\u00fbr la matrice initiale) :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>      ((\u2296\u2349) \u2363 4) m\n1 2 3\n4 5 6\n7 8 9<\/code><\/pre>\n\n\n\n<p>D&rsquo;o\u00f9 cette <strong>version finale<\/strong> en <strong>APL<\/strong> :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>      rotation \u2190 { (\u2349\u233d) \u2363 (4|\u237a) \u22a2 \u2375 }\n\n      3 rotation 3 3 \u2374 \u23739\n7 4 1\n8 5 2\n9 6 3\n      1 rotation 4 4 \u2374 \u237316\n4 8 12 16\n3 7 11 15\n2 6 10 14\n1 5  9 13<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Javascript<\/h3>\n\n\n\n<p>La biblioth\u00e8que JavaScript <a rel=\"noreferrer noopener\" href=\"https:\/\/ramdajs.com\/docs\/#transpose\" target=\"_blank\">Ramda<\/a> permet \u00e9galement de faire des renversements et de transposer des tableaux. On peut donc comme en APL remplacer la <strong>rotation anti-horaire<\/strong> par la combinaison <strong>transpose<\/strong> et <strong>reverse<\/strong>. <a rel=\"noreferrer noopener\" href=\"https:\/\/ramdajs.com\/repl\/?v=0.28.0#?R.transpose%28%5B%5B1%2C%202%5D%2C%20%5B3%2C%204%5D%5D%29.reverse%28%29%0A%0A\" target=\"_blank\">Exemple que vous pouvez tester ici<\/a> :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>R.transpose(&#091;&#091;1, 2], &#091;3, 4]]).reverse()\n&#091;&#091;2, 4], &#091;1, 3]]<\/code><\/pre>\n\n\n\n<p>Version finale <strong>r\u00e9cursive<\/strong> <a rel=\"noreferrer noopener\" href=\"https:\/\/ramdajs.com\/repl\/?v=0.28.0#?var%20rotation%20%3D%20%28matrice%2C%20n%29%20%3D%3E%20%7B%0A%20%20n%20%25%3D%204%0A%20%20if%20%28n%20%3D%3D%200%29%20return%20matrice%0A%20%20matrice%20%3D%20R.transpose%28matrice%29.reverse%28%29%0A%20%20return%20rotation%28matrice%2C%20n%20-%201%29%0A%7D%0A%0Arotation%28%5B%5B1%2C%202%5D%2C%20%5B3%2C%204%5D%5D%2C%201%29%0A%0A\" target=\"_blank\">\u00e0 tester ici<\/a> : <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>var rotation = (matrice, n) =&gt; {\n  n %= 4                                     \/\/ reste division par 4\n  if (n == 0) return matrice                 \/\/ fin r\u00e9cursivit\u00e9\n  matrice = R.transpose(matrice).reverse()   \/\/ rotation anti-horaire   \n  return rotation(matrice, n - 1)            \/\/ appel r\u00e9cursif\n}\n\n&gt;&gt; rotation(&#091;&#091;1, 2], &#091;3, 4]], 1)\n&#091;&#091;2, 4], &#091;1, 3]]<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">JavaScript &amp; Python : Version sans biblioth\u00e8que<\/h2>\n\n\n\n<p>Pour se fixer les id\u00e9es, supposons que l&rsquo;on ait une matrice 3 x 3. Observez que faire une rotation anti-horaire, c&rsquo;est <strong>remplacer<\/strong> la <strong>1ere ligne<\/strong> par la <strong>derni\u00e8re colonne<\/strong>, la 2e ligne par la 2e colonne et la 3e ligne par la 1ere colonne :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>matrice initiale\n\n1 2 3\n4 5 6\n7 8 9\n\nrotation anti-horaire\n\n3 6 9       \/\/ 1ere ligne = 3e colonne de la matrice initiale\n2 5 8       \/\/ 2e ligne = 2e colonne de la matrice initiale\n1 4 7       \/\/ 3e ligne = 3e colonne de la matrice initiale<\/code><\/pre>\n\n\n\n<p>Dit autrement, faire une <strong>rotation anti-horaire<\/strong>, c&rsquo;est prendre les <strong>colonnes<\/strong> de la <strong>droite vers la gauche<\/strong> et les <strong>\u00e9crire en lignes<\/strong>.<\/p>\n\n\n\n<p>Ce que l&rsquo;on peut traduire en Python ou JavaScript par :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>anti_horaire = matrice =&gt; {\n    res = &#091; ];                           \/\/ Matrice finale\n    taille = matrice.length;             \/\/ Taille matrice\n    for (l = 0; l &lt; taille; l++) {       \/\/ Cr\u00e9ation de chaque ligne\n        ligne = &#091; ];                     \/\/ Initialisation \n        for (i = 0; i &lt; taille; i++) {   \/\/ Chaque \u00e9l\u00e9ment de la ligne \n            ligne.push(matrice&#091;i]&#091;taille - l - 1])\n        };\n        res.push(ligne)                  \/\/ Ajout de la ligne\n    };\n    return res;                          \/\/ On retourne le r\u00e9sultat\n}\n\n&gt;&gt; anti_horaire(&#091;&#091;1,2,3], &#091;4,5,6], &#091;7,8,9]])\n&#091;3, 6, 9]\n&#091;2, 5, 8]\n&#091;1, 4, 7]<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">javascript<\/h3>\n\n\n\n<p>Comme il s&rsquo;agit de <strong>transformer<\/strong> chacune des lignes, on peut \u00e9galement utiliser <strong>map<\/strong>. Voici ci-dessous la m\u00eame version du programme pr\u00e9c\u00e9dent. Le <strong>matrice[0]<\/strong> permet de r\u00e9cup\u00e9rer la premi\u00e8re ligne de la matrice et donc un <strong>tableau qui a la largeur de cette matrice<\/strong>, son contenu ne nous int\u00e9resse pas puisqu&rsquo;il va \u00eatre calcul\u00e9, d&rsquo;o\u00f9 le <strong>_<\/strong>. Pour chaque num\u00e9ro de ligne (variable <code>l<\/code>), on remplace les \u00e9l\u00e9ments par la colonne correspondante en partant de la droite (<strong>x.length &#8211; l &#8211; 1<\/strong>):<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>anti_horaire = matrice =&gt; \n    matrice&#091;0].map((_,l) =&gt; matrice.map(x =&gt; x&#091;x.length - l - 1]))<\/code><\/pre>\n\n\n\n<p><strong>Version finale<\/strong> (sans biblioth\u00e8que) en <strong>JavaScript<\/strong> :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>const rotation = (matrice, n) =&gt; {\n    for (i = 0; i &lt; n % 4; i++)\n     matrice = matrice&#091;0].map((_,l) =&gt; \n                matrice.map(x =&gt; x&#091;x.length - l - 1]))\n    return matrice\n}\n\n&gt;&gt; rotation(&#091;&#091;1,2,3], &#091;4,5,6], &#091;7,8,9]], 1)\n&#091;3, 6, 9]\n&#091;2, 5, 8]\n&#091;1, 4, 7]\n\n&gt;&gt; rotation(&#091;&#091;1,2,3], &#091;4,5,6], &#091;7,8,9]], 2)\n&#091;9, 8, 7]\n&#091;6, 5, 4]\n&#091;3, 2, 1]<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Python<\/h3>\n\n\n\n<p>Comme nous l&rsquo;avons vu, faire une <strong>rotation anti-horaire<\/strong>, c&rsquo;est faire une <strong>transpos\u00e9e<\/strong> (remplacer la 1ere ligne par la 1ere colonne, la 2e ligne par la 2e colonne etc.) <strong>puis inverser<\/strong> l&rsquo;ordre des <strong>lignes<\/strong> :<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/06\/image-14.png\"><img loading=\"lazy\" decoding=\"async\" width=\"451\" height=\"91\" src=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/06\/image-14.png\" alt=\"\" class=\"wp-image-470\" srcset=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/06\/image-14.png 451w, https:\/\/blog.univ-angers.fr\/mathsinfo\/files\/2022\/06\/image-14-300x61.png 300w\" sizes=\"auto, (max-width: 451px) 100vw, 451px\" \/><\/a><\/figure>\n\n\n\n<p>Voici comment <strong>inverser les lignes<\/strong> en Python :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&gt;&gt; &#091;&#091;1, 2, 3], &#091;4, 5, 6], &#091;7, 8, 9]] &#091;::-1]\n&#091;&#091;7, 8, 9], &#091;4, 5, 6], &#091;1, 2, 3]]<\/code><\/pre>\n\n\n\n<p>Ce qui donne ce <strong>programme final<\/strong> :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def rotation(matrice, n):\n  for _ in range(n % 4):\n    matrice = &#091;&#091;r&#091;i] for r in matrice] for i in range(len(matrice))]&#091;::-1]\n  return matrice<\/code><\/pre>\n\n\n\n<p>Ou cette autre <strong>version avanc\u00e9e<\/strong> qui utilise la notion de <strong>d\u00e9paquetage<\/strong> avec <strong>zip<\/strong> et <strong>*<\/strong> :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def rotation(matrice, n):\n  for _ in range(n % 4):\n    matrice = &#091;list(col) for col in list(zip(*matrice))]&#091;::-1]\n  return matrice<\/code><\/pre>\n\n\n\n<p>Quelques exemples pour mieux comprendre <strong>zip<\/strong> et <strong>*<\/strong> :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&gt;&gt; &#091;* &#091;&#091;1, 2], &#091;3, 4]]]           # Exemple n\u00b01 de d\u00e9paquetage\n&#091;&#091;1, 2], &#091;3, 4]]\n\n&gt;&gt; &#091;* {1, 2, 3}]                  # Exemple n\u00b02 de d\u00e9paquetage\n&#091;1, 2, 3]\n\n&gt;&gt; &#091;* 'abcd']                     # Exemple n\u00b03 de d\u00e9paquetage\n&#091;'a', 'b', 'c', 'd']\n\n&gt;&gt; list(zip(&#091;1,2], &#091;3,4]))\n&#091;(1, 3), (2, 4)]\n\n&gt;&gt; list(zip(&#091;&#091;1, 2], &#091;3, 4]]))    # ne fonctionne pas\n&#091;(&#091;1, 2],), (&#091;3, 4],)]\n\n&gt;&gt; list(zip(* &#091;&#091;1, 2], &#091;3, 4]]))  # Il faut d\u00e9j\u00e0 d\u00e9paqueter\n&#091;(1, 3), (2, 4)]<\/code><\/pre>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>R\u00e9sum\u00e9 en fran\u00e7ais : On vous donne une matrice carr\u00e9e et un nombre n, vous devez renvoyer cette matrice dont les tous les termes ont \u00e9t\u00e9 tourn\u00e9s (n rotations) dans le sens anti-horaire. Exemple avec une matrice 3 x 3 &hellip; <a href=\"https:\/\/blog.univ-angers.fr\/mathsinfo\/2022\/06\/12\/kata11\/\">Continuer la lecture <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":4913,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6],"tags":[],"class_list":["post-460","post","type-post","status-publish","format-standard","hentry","category-twitter"],"_links":{"self":[{"href":"https:\/\/blog.univ-angers.fr\/mathsinfo\/wp-json\/wp\/v2\/posts\/460","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.univ-angers.fr\/mathsinfo\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.univ-angers.fr\/mathsinfo\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.univ-angers.fr\/mathsinfo\/wp-json\/wp\/v2\/users\/4913"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.univ-angers.fr\/mathsinfo\/wp-json\/wp\/v2\/comments?post=460"}],"version-history":[{"count":19,"href":"https:\/\/blog.univ-angers.fr\/mathsinfo\/wp-json\/wp\/v2\/posts\/460\/revisions"}],"predecessor-version":[{"id":660,"href":"https:\/\/blog.univ-angers.fr\/mathsinfo\/wp-json\/wp\/v2\/posts\/460\/revisions\/660"}],"wp:attachment":[{"href":"https:\/\/blog.univ-angers.fr\/mathsinfo\/wp-json\/wp\/v2\/media?parent=460"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.univ-angers.fr\/mathsinfo\/wp-json\/wp\/v2\/categories?post=460"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.univ-angers.fr\/mathsinfo\/wp-json\/wp\/v2\/tags?post=460"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}