<?xml version='1.0' encoding='utf-8' ?>
<!--  If you are running a bot please visit this policy page outlining rules you must respect. http://www.livejournal.com/bots/  -->
<rss version='2.0' xmlns:lj='http://www.livejournal.org/rss/lj/1.0/' xmlns:media='http://search.yahoo.com/mrss/' xmlns:atom10='http://www.w3.org/2005/Atom'>
<channel>
  <title>minds2web</title>
  <link>http://artemvoroztsov.livejournal.com/</link>
  <description>minds2web - LiveJournal.com</description>
  <lastBuildDate>Thu, 31 May 2007 23:03:02 GMT</lastBuildDate>
  <generator>LiveJournal / LiveJournal.com</generator>
  <lj:journal>artemvoroztsov</lj:journal>
  <lj:journalid>10836060</lj:journalid>
  <lj:journaltype>personal</lj:journaltype>
  <atom10:link rel='hub' href='http://pubsubhubbub.appspot.com/' />
  <image>
    <url>http://l-userpic.livejournal.com/50122238/10836060</url>
    <title>minds2web</title>
    <link>http://artemvoroztsov.livejournal.com/</link>
    <width>100</width>
    <height>100</height>
  </image>

<item>
  <guid isPermaLink='true'>http://artemvoroztsov.livejournal.com/528.html</guid>
  <pubDate>Thu, 31 May 2007 23:03:02 GMT</pubDate>
  <title>Уроки Ruby. Как с помощью рубина получить волшебные кубики?</title>
  <link>http://artemvoroztsov.livejournal.com/528.html</link>
  <description>&lt;p&gt;На одной из олимпиад по программированию была следующая простая задача на перебор (см. ниже). И был приведен авторский код на языке C++ (см. ниже). Я посмотрел на все это и понял, что нужно немедленно переписать все на Ruby (см. еще ниже).&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;a name=&quot;cutid1&quot;&gt;&lt;/a&gt;Читать далее ..
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&amp;nbsp;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;&lt;a name=&quot;_cfc_c__qn_gdp_g_ki_cn_p_g_m_dkm&quot;&gt;&lt;/a&gt;Задача &amp;quot;Волшебные игральные кубики&amp;quot;&lt;/h2&gt;&lt;p&gt;Стандартный игральный кубик имеет 6 граней, на которых написаны числа {1,2,3,4,5,6}. Давайте рассмотрим нестандартные кубики, на гранях которых могут быть поставлены различные числа с возможными повторениями. Представьте себе, что у меня есть 3 таких кубика. Я предлагаю своему партнеру выбрать любой из этих кубиков, который ему больше понравился, а сам беру себе другой кубик из двух оставшихся. Далее мы начинаем играть: каждый бросает свой кубик, и выигрывает тот, на чьем кубике выпадет большее число. Оказывается, что при большом числе бросаний в среднем я буду в выигрыше, то есть я буду чаще выигрывать у партнера. Даже если партнер поменяет кубик, например, возьмет кубик, которым играл я, то он все равно будет проигрывать, если я воспользуюсь правом выбрать себе кубик из двух оставшихся. Может ли такое быть? Оказывается, может. Весь секрет в числах, которые расставлены на гранях кубиков. Пусть на гранях трех кубиков числа расставлены так:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;первый кубик 1, 1, 4, 4, 7, 7,&lt;/li&gt;&lt;li&gt;второй кубик - 2, 2, 5, 5, 5, 5,&lt;/li&gt;&lt;li&gt;третий кубик - 3, 3, 3, 3, 6, 6.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Нетрудно проверить, что второй кубик будет выигрывать у первого в среднем в пяти случаях из девяти, а проигрывать только в 4-х случаях из 9. Третий кубик будет выигрывать у второго также в 5 случаях из 9. А первый будет выигрывать у третьего также в 5 случаях из 9. (Правильнее сказать: в 20 случаях из 36, так как количество вариантов выпадения граней двух кубиков равно 6 6. Но это то же самое, так как дроби можно сокращать.)&lt;/p&gt;&lt;p&gt;&lt;font color=&quot;#000080&quot;&gt;Сформулируем сказанное в других терминах. Кубики можно сравнивать друг с другом: кубик A &amp;quot;сильнее&amp;quot; кубика B, если в среднем на кубике A выпадает число большее, чем число, которое выпадает на кубике B. На практике сравнить кубики несложно - нужно просто много раз кинуть два кубика одновременно и считать сколько раз A выиграл B, B выиграл A, и сколько раз была ничья. Но умелый программист может написать функцию test(A,B), которая абсолютно точно выдаст какой из кубиков &amp;quot;сильнее&amp;quot;. Удивительный факт заключается в том, что бывают тройки кубиков A, B, C в которых A сильнее B, B сильнее C, и C сильнее A, то есть, говоря математическим языком, отношение &amp;quot;сильнее&amp;quot; не транзитивно и ориентированном графе, представляющем это отношение, есть циклы длины 3. &lt;/font&gt;&lt;/p&gt;&lt;p&gt;Ваша задача заключается в том, чтобы, используя наименьшее количество различных чисел, найти их расстановку (конечно, с повторениями) на гранях трех кубиков такую, чтобы кубики обладали описанным выше &amp;quot;волшебным&amp;quot; свойством.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h2&gt;&lt;a name=&quot;_g_gpkg_pc_Cbb_c__q__pgk__g__gp_&quot;&gt;&lt;/a&gt;Решение на C++ (автор неизвестен)&lt;/h2&gt;&lt;div class=&quot;fragment&quot;&gt;&lt;pre&gt;&lt;font color=&quot;#000080&quot;&gt;#include&lt;/font&gt; &amp;lt;iostream&amp;gt;
&lt;font color=&quot;#a52a2a&quot;&gt;using&lt;/font&gt; &lt;font color=&quot;#a52a2a&quot;&gt;namespace&lt;/font&gt; std;
&lt;font color=&quot;#a52a2a&quot;&gt;const&lt;/font&gt; &lt;font color=&quot;#a52a2a&quot;&gt;int&lt;/font&gt;  Q = 6,  &lt;font color=&quot;#008000&quot;&gt;// число граней игрального кубика&lt;/font&gt;
          Mmax = 1000; 
&lt;font color=&quot;#a52a2a&quot;&gt;int&lt;/font&gt; N;     &lt;font color=&quot;#008000&quot;&gt;// число найденных решений&lt;/font&gt;
&lt;font color=&quot;#a52a2a&quot;&gt;int&lt;/font&gt;  P,    &lt;font color=&quot;#008000&quot;&gt;// число возможных цифр&lt;/font&gt;
     M;    &lt;font color=&quot;#008000&quot;&gt;// число игральных кубиков &amp;mdash; число&lt;/font&gt;
           &lt;font color=&quot;#008000&quot;&gt;//  наборов размера Q из P элементов&lt;/font&gt;
           &lt;font color=&quot;#008000&quot;&gt;//  с возможными повторениями.  &lt;/font&gt;
&lt;font color=&quot;#a52a2a&quot;&gt;int&lt;/font&gt;  C[Mmax][Q],       &lt;font color=&quot;#008000&quot;&gt;// коллекция кубиков.&lt;/font&gt;
     E[Q] ;

&lt;font color=&quot;#a52a2a&quot;&gt;int&lt;/font&gt; test(&lt;font color=&quot;#a52a2a&quot;&gt;int&lt;/font&gt; i, &lt;font color=&quot;#a52a2a&quot;&gt;int&lt;/font&gt; j) {   &lt;font color=&quot;#008000&quot;&gt;// сравнение двух кубиков C[i] и C[j]&lt;/font&gt;
   &lt;font color=&quot;#a52a2a&quot;&gt;int&lt;/font&gt; k, l, t = 0;
   &lt;font color=&quot;#a52a2a&quot;&gt;for&lt;/font&gt; (k = 0; k &amp;lt; Q; k++)  
       &lt;font color=&quot;#a52a2a&quot;&gt;for&lt;/font&gt; (l = 0; l &amp;lt; Q; l++)
           &lt;font color=&quot;#a52a2a&quot;&gt;if&lt;/font&gt; (C[i][k] &amp;gt; C[j][l]) 
               t++;
           &lt;font color=&quot;#a52a2a&quot;&gt;else&lt;/font&gt; 
               &lt;font color=&quot;#a52a2a&quot;&gt;if&lt;/font&gt; (C[i][k] &amp;lt; C[j][l]) t--;
   &lt;font color=&quot;#a52a2a&quot;&gt;if&lt;/font&gt; (t &amp;gt; 0) &lt;font color=&quot;#a52a2a&quot;&gt;return&lt;/font&gt; 1; 
   &lt;font color=&quot;#a52a2a&quot;&gt;else&lt;/font&gt; &lt;font color=&quot;#a52a2a&quot;&gt;if&lt;/font&gt; (t &amp;lt; 0) &lt;font color=&quot;#a52a2a&quot;&gt;return&lt;/font&gt; -1;
   &lt;font color=&quot;#a52a2a&quot;&gt;else&lt;/font&gt; &lt;font color=&quot;#a52a2a&quot;&gt;return&lt;/font&gt; 0;
}

&lt;font color=&quot;#a52a2a&quot;&gt;int&lt;/font&gt; main(){
   &lt;font color=&quot;#a52a2a&quot;&gt;int&lt;/font&gt; j, k, q, t;

   M = 0;
   N = 0;
   cout &amp;lt;&amp;lt; &amp;quot;&lt;font color=&quot;#0000ff&quot;&gt;Введите число цифр P=&lt;/font&gt;&amp;quot;;
   cin  &amp;gt;&amp;gt; P; &lt;font color=&quot;#008000&quot;&gt;// P = 4;&lt;/font&gt;
   &lt;font color=&quot;#008000&quot;&gt;// Построение множества всех кубиков&lt;/font&gt;
   &lt;font color=&quot;#a52a2a&quot;&gt;for&lt;/font&gt; (q = 0; q &amp;lt; Q; q++) 
       C[0][q] = E[q] = 1;
   &lt;font color=&quot;#a52a2a&quot;&gt;for&lt;/font&gt; (M = 1; M &amp;lt; Mmax; M++) {
       &lt;font color=&quot;#a52a2a&quot;&gt;for&lt;/font&gt; (q = Q - 1; q &amp;gt;= 0; q--) {
           &lt;font color=&quot;#a52a2a&quot;&gt;if&lt;/font&gt; (E[q] &amp;lt; P) {
               &lt;font color=&quot;#a52a2a&quot;&gt;int&lt;/font&gt; s;
               E[q]++;
               &lt;font color=&quot;#a52a2a&quot;&gt;for&lt;/font&gt; (s = q + 1; s &amp;lt; Q; s++)
                   E[s] = E[q];
               &lt;font color=&quot;#a52a2a&quot;&gt;break&lt;/font&gt;;
           }
       }
       &lt;font color=&quot;#a52a2a&quot;&gt;if&lt;/font&gt; (q &amp;lt; 0) &lt;font color=&quot;#a52a2a&quot;&gt;break&lt;/font&gt;;
       &lt;font color=&quot;#a52a2a&quot;&gt;for&lt;/font&gt; (q = 0; q &amp;lt; Q; q++) 
           C[M][q] = E[q];
    }

    &lt;font color=&quot;#a52a2a&quot;&gt;if&lt;/font&gt; (M &amp;gt; Mmax)
       cout &amp;lt;&amp;lt; &amp;quot;&lt;font color=&quot;#0000ff&quot;&gt;Только &lt;/font&gt;&amp;quot; &amp;lt;&amp;lt; Mmax &amp;lt;&amp;lt; &amp;quot;&lt;font color=&quot;#0000ff&quot;&gt; кубиков будут рассматриваться.\n&lt;/font&gt;&amp;quot;;

    &lt;font color=&quot;#a52a2a&quot;&gt;for&lt;/font&gt; (E[0] = 0; E[0] &amp;lt; M - 2; E[0]++) { &lt;font color=&quot;#008000&quot;&gt;// Перебор решений&lt;/font&gt;
       &lt;font color=&quot;#a52a2a&quot;&gt;for&lt;/font&gt; (E[1] = E[0] + 1; E[1] &amp;lt; M - 1; E[1]++) {
           t = test(E[0], E[1]);
           &lt;font color=&quot;#a52a2a&quot;&gt;if&lt;/font&gt; (t != 0) {
               &lt;font color=&quot;#a52a2a&quot;&gt;for&lt;/font&gt; (E[2]=E[1]+1; E[2]&amp;lt;M; E[2]++) {
                   &lt;font color=&quot;#a52a2a&quot;&gt;if&lt;/font&gt; (t == test(E[1],E[2]) &amp;amp;&amp;amp; t == test(E[2],E[0]) ) {
                       &lt;font color=&quot;#a52a2a&quot;&gt;for&lt;/font&gt; (j = 0; j &amp;lt; 3; j++) {
                           &lt;font color=&quot;#008000&quot;&gt;// Вывод решения&lt;/font&gt;
                           cout &amp;lt;&amp;lt; &amp;quot;&lt;font color=&quot;#0000ff&quot;&gt;(&lt;/font&gt;&amp;quot;;
                           &lt;font color=&quot;#a52a2a&quot;&gt;for&lt;/font&gt; (q = 0; q &amp;lt; Q; q++) { 
                               &lt;font color=&quot;#a52a2a&quot;&gt;if&lt;/font&gt; (q) cout &amp;lt;&amp;lt; &amp;quot;&lt;font color=&quot;#0000ff&quot;&gt;,&lt;/font&gt;&amp;quot;;
                               cout &amp;lt;&amp;lt; C[E[j]][q];
                           }
                           cout &amp;lt;&amp;lt; &amp;quot;&lt;font color=&quot;#0000ff&quot;&gt;)&lt;/font&gt;&amp;quot;;
                           &lt;font color=&quot;#a52a2a&quot;&gt;if&lt;/font&gt; (t == 1)  cout &amp;lt;&amp;lt; &amp;quot;&lt;font color=&quot;#0000ff&quot;&gt;&amp;gt;&lt;/font&gt;&amp;quot;;
                           &lt;font color=&quot;#a52a2a&quot;&gt;if&lt;/font&gt; (t == -1) cout &amp;lt;&amp;lt; &amp;quot;&lt;font color=&quot;#0000ff&quot;&gt;&amp;lt;&lt;/font&gt;&amp;quot;;
                           cout &amp;lt;&amp;lt; endl;
                       }
                       cout &amp;lt;&amp;lt; endl;
                       N++;
                   }
               }
           }
       }
   }
   cout &amp;lt;&amp;lt; &amp;quot;&lt;font color=&quot;#0000ff&quot;&gt;M N: &lt;/font&gt;&amp;quot; &amp;lt;&amp;lt; M &amp;lt;&amp;lt; &apos; &apos; &amp;lt;&amp;lt; N &amp;lt;&amp;lt; endl;
   &lt;font color=&quot;#a52a2a&quot;&gt;return&lt;/font&gt; 0;
}&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h2&gt;&lt;a name=&quot;_g_gpkg_pc_Ruby_&quot;&gt;&lt;/a&gt;Решение на Ruby.&lt;/h2&gt;&lt;p&gt;Это задача решается методом перебора. По сути, нам нужно перебрать различные сочетания элементов из промежутка &lt;code&gt;(1..P)&lt;/code&gt; с возможными повторениями, и для получившегося множества сочетаний перебрать всевозможные тройки (уже без повторения). Естественно для этого написать методы для экземпляров класса &lt;code&gt;Array&lt;/code&gt; - массивов.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class=&quot;fragment&quot;&gt;&lt;pre&gt;&lt;font color=&quot;#a52a2a&quot;&gt;class&lt;/font&gt; &lt;a target=&quot;Array&quot;&gt;Array&lt;/a&gt;
   &lt;font color=&quot;#008000&quot;&gt;# перебрать все наборы с возможными повторениями&lt;/font&gt;
   &lt;font color=&quot;#a52a2a&quot;&gt;def&lt;/font&gt; tuples (&lt;font color=&quot;#008080&quot;&gt;size&lt;/font&gt;, &amp;amp;block)
       tuples0(&lt;font color=&quot;#008080&quot;&gt;size&lt;/font&gt;,[],0,block)
   &lt;font color=&quot;#a52a2a&quot;&gt;end&lt;/font&gt;
       
   private
   &lt;font color=&quot;#008000&quot;&gt;# перебрать все наборы элементов с возможными &lt;/font&gt;
   &lt;font color=&quot;#008000&quot;&gt;# повторениями, при условии, что уже набран&lt;/font&gt;
   &lt;font color=&quot;#008000&quot;&gt;# частично набор ary, и в него нужно добрать &lt;/font&gt;
   &lt;font color=&quot;#008000&quot;&gt;# элементы из хвоста массива self[i..].&lt;/font&gt;
   &lt;font color=&quot;#a52a2a&quot;&gt;def&lt;/font&gt; tuples0(&lt;font color=&quot;#008080&quot;&gt;size&lt;/font&gt;,ary,i,block)
       &lt;font color=&quot;#a52a2a&quot;&gt;if&lt;/font&gt; ary.&lt;font color=&quot;#008080&quot;&gt;size&lt;/font&gt; == &lt;font color=&quot;#008080&quot;&gt;size&lt;/font&gt;
           &lt;font color=&quot;#008000&quot;&gt;# получен очередной набор&lt;/font&gt;
           &lt;font color=&quot;#008000&quot;&gt;# отдадим его ассоциированному блоку&lt;/font&gt;
           block[ary] 
       &lt;font color=&quot;#a52a2a&quot;&gt;elsif&lt;/font&gt; i &amp;lt; &lt;font color=&quot;#a52a2a&quot;&gt;self&lt;/font&gt;.&lt;font color=&quot;#008080&quot;&gt;size&lt;/font&gt;
           &lt;font color=&quot;#008000&quot;&gt;# возьмем self[i]&lt;/font&gt;
           ary.&lt;font color=&quot;#008080&quot;&gt;push&lt;/font&gt; &lt;font color=&quot;#a52a2a&quot;&gt;self&lt;/font&gt;[i]
           tuples0(&lt;font color=&quot;#008080&quot;&gt;size&lt;/font&gt;,ary,i,block)
           ary.&lt;font color=&quot;#008080&quot;&gt;pop&lt;/font&gt;

           &lt;font color=&quot;#008000&quot;&gt;# или пропустим self[i]&lt;/font&gt;
           tuples0(&lt;font color=&quot;#008080&quot;&gt;size&lt;/font&gt;,ary,i+1,block) 
       &lt;font color=&quot;#a52a2a&quot;&gt;end&lt;/font&gt;
   &lt;font color=&quot;#a52a2a&quot;&gt;end&lt;/font&gt;
&lt;font color=&quot;#a52a2a&quot;&gt;end&lt;/font&gt;

&lt;font color=&quot;#008000&quot;&gt;# сгенерируем сочетания 3-х элементов из 5 &lt;/font&gt;
&lt;font color=&quot;#008000&quot;&gt;# с возможными повторениями &lt;/font&gt;
(1..5).&lt;font color=&quot;#008080&quot;&gt;to_a&lt;/font&gt;.tuples(3) &lt;font color=&quot;#a52a2a&quot;&gt;do&lt;/font&gt; |tuple|
   &lt;font color=&quot;#008080&quot;&gt;puts&lt;/font&gt; tuple.&lt;font color=&quot;#008080&quot;&gt;inspect&lt;/font&gt;
&lt;font color=&quot;#a52a2a&quot;&gt;end&lt;/font&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;Вывод программы:&lt;/p&gt;&lt;div class=&quot;fragment&quot;&gt;&lt;pre&gt;
[1, 1, 1]
[1, 1, 2]
[1, 1, 3]
[1, 1, 4]
[1, 1, 5]
[1, 2, 2]
[1, 2, 3]
[1, 2, 4]
[1, 2, 5]
[1, 3, 3]
[1, 3, 4]
[1, 3, 5]
[1, 4, 4]
[1, 4, 5]
[1, 5, 5]
[2, 2, 2]
[2, 2, 3]
[2, 2, 4]
[2, 2, 5]
[2, 3, 3]
[2, 3, 4]
[2, 3, 5]
[2, 4, 4]
[2, 4, 5]
[2, 5, 5]
[3, 3, 3]
[3, 3, 4]
[3, 3, 5]
[3, 4, 4]
[3, 4, 5]
[3, 5, 5]
[4, 4, 4]
[4, 4, 5]
[4, 5, 5]
[5, 5, 5]&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;Предъявленный метод &lt;code&gt;tuples&lt;/code&gt; у экземпляров класса &lt;code&gt;Array&lt;/code&gt; генерирует различные сочетания с возможными повторениями из элементов массива. Этот метод вызывается как метод конкретного массива, который внутри определений имеет имя &lt;code&gt;self&lt;/code&gt; (сам объект). Алгоритм генерации основан на методе рекурсии. Введем в задачу дополнительные параметры - &lt;code&gt;ary&lt;/code&gt; и &lt;code&gt;i&lt;/code&gt;:&lt;/p&gt;&lt;p&gt;Подзадача: Пусть у нас уже взято несколько элементов, и они собраны в массиве ary. Необходимо доложить в этот набор элементы так, чтобы он имел размер &lt;code&gt;size&lt;/code&gt;, используя при этом только элементы хвоста массива: &lt;code&gt;self[i]&lt;/code&gt;, &lt;code&gt;self[i+1]&lt;/code&gt;, &amp;hellip;&lt;/p&gt;&lt;p&gt;Эту подзадачу решает функция &lt;code&gt;tuples0(size,ary,i,block)&lt;/code&gt;, при этом эта подзадача легко сводится сама к себе, и её можно решить, используя рекурсию.&lt;/p&gt;&lt;p&gt;Задача. Загрузите и установите Ruby (&lt;a target=&quot;_top&quot; href=&quot;http://www.ruby-lang.org/en/downloads&quot;&gt;http://www.ruby-lang.org/en/downloads&lt;/a&gt;). Используя редактор &lt;span style=&quot;background: rgb(248, 248, 255) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;&quot;&gt;&lt;font color=&quot;#0000ff&quot;&gt;SciTe&lt;/font&gt;&lt;/span&gt;&lt;a href=&quot;http://acm.mipt.ru/twiki/bin/edit/Ruby/SciTe?topicparent=Ruby.MagicCubes&quot;&gt;?&lt;/a&gt;, который поставляется вместе с дистрибутивом, наберите данный текст программы и запустите её, нажав на F5. Создайте новые функции &lt;code&gt;subsets&lt;/code&gt; и &lt;code&gt;subsets0&lt;/code&gt;, которые генерирую наборы без повторений элементов. Для этого нужно взять за основу функции &lt;code&gt;tuples&lt;/code&gt; и &lt;code&gt;tuples0&lt;/code&gt;, а именно, сначала нужно точно повторить их (скопировать), заменить везде tuples на subsets, а также заменить строку&lt;/p&gt;&lt;p&gt;&lt;code&gt;tuples0(size,ary,i,block)&lt;/code&gt;&lt;/p&gt;&lt;p&gt;на строку&lt;/p&gt;&lt;p&gt;&lt;code&gt;subsets0(size,ary,i+1,block)&lt;/code&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;Решите эту задачу, не поленитесь. Проверить работу можно с помощью строки&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class=&quot;fragment&quot;&gt;&lt;pre&gt;
(1..5).&lt;font color=&quot;#008080&quot;&gt;to_a&lt;/font&gt;.subsets(3) { |subset|  &lt;font color=&quot;#008080&quot;&gt;puts&lt;/font&gt; subset.&lt;font color=&quot;#008080&quot;&gt;inspect&lt;/font&gt; }&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Эта строка должна вывести 10 различных сочетаний 3 элементов из 5 первых натуральных чисел. без повторений&lt;/p&gt;&lt;p&gt;Для решения задачи о волшебных тройках осталось сделать совсем немного - определить метод сравнения двух наборов. Для этого давайте переопределим оператор &amp;lt;=&amp;gt; так, чтобы он возвращал -1, 0 или 1, в зависимости от того, какой из двух наборов чисел выигрывает:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;1 - первый выигрывает;&lt;/li&gt;&lt;li&gt;0 - ничья;&lt;/li&gt;&lt;li&gt;-1 - второй выигрывает.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Этот оператор именно таким образом определен для обыкновенных чисел. Вот определение этого метода сравнения двух наборов (&amp;quot;абстрактных игральных кубиков&amp;quot;):&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class=&quot;fragment&quot;&gt;&lt;pre&gt;&lt;font color=&quot;#a52a2a&quot;&gt;class&lt;/font&gt; &lt;a target=&quot;Array&quot;&gt;Array&lt;/a&gt;
   &lt;font color=&quot;#a52a2a&quot;&gt;def&lt;/font&gt; &amp;lt;=&amp;gt;(ary)
       res = 0
       &lt;font color=&quot;#a52a2a&quot;&gt;self&lt;/font&gt;.&lt;font color=&quot;#008080&quot;&gt;each&lt;/font&gt; &lt;font color=&quot;#a52a2a&quot;&gt;do&lt;/font&gt; |x|
           ary.&lt;font color=&quot;#008080&quot;&gt;each&lt;/font&gt; &lt;font color=&quot;#a52a2a&quot;&gt;do&lt;/font&gt; |y|
               res += (x&amp;lt;=&amp;gt;y)
           &lt;font color=&quot;#a52a2a&quot;&gt;end&lt;/font&gt;
       &lt;font color=&quot;#a52a2a&quot;&gt;end&lt;/font&gt;
   &lt;font color=&quot;#a52a2a&quot;&gt;end&lt;/font&gt;
&lt;font color=&quot;#a52a2a&quot;&gt;end&lt;/font&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Заметьте, что в Ruby можно свободно &amp;quot;дописывать&amp;quot; существующие классы, добавляя в них новые методы и переопределяя существующие.&lt;/p&gt;&lt;p&gt;Функции &lt;code&gt;subsets&lt;/code&gt; и &lt;code&gt;tuples&lt;/code&gt; слишком сильно повторяют друг друга. Это не соответствует основной концепции Ruby - не повторяйся (принцип DRY - don&apos;t&apos; repeat yourself). Этих повторений можно избежать, введя дополнительный аргумент у функции &lt;code&gt;tuples0&lt;/code&gt;. Кроме того, хотелось бы, чтобы функции &lt;code&gt;tuples&lt;/code&gt; и &lt;code&gt;subsets&lt;/code&gt;, если их вызывать без ассоциированного блока, просто возвращали массив наборов. Это сделано в приведённом ниже полном коде программы.&lt;/p&gt;&lt;p&gt;Решение задачи выглядит следующим образом:&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class=&quot;fragment&quot;&gt;&lt;pre&gt;&lt;font color=&quot;#a52a2a&quot;&gt;class&lt;/font&gt; &lt;a target=&quot;Array&quot;&gt;Array&lt;/a&gt;
   &lt;font color=&quot;#a52a2a&quot;&gt;def&lt;/font&gt; &amp;lt;=&amp;gt;(ary)
       res = 0
       &lt;font color=&quot;#a52a2a&quot;&gt;self&lt;/font&gt;.&lt;font color=&quot;#008080&quot;&gt;each&lt;/font&gt; &lt;font color=&quot;#a52a2a&quot;&gt;do&lt;/font&gt; |x|
           ary.&lt;font color=&quot;#008080&quot;&gt;each&lt;/font&gt; &lt;font color=&quot;#a52a2a&quot;&gt;do&lt;/font&gt; |y|
               res += (x&amp;lt;=&amp;gt;y)
           &lt;font color=&quot;#a52a2a&quot;&gt;end&lt;/font&gt;
       &lt;font color=&quot;#a52a2a&quot;&gt;end&lt;/font&gt;
       res &amp;lt;=&amp;gt; 0
   &lt;font color=&quot;#a52a2a&quot;&gt;end&lt;/font&gt;
   
   &lt;font color=&quot;#008000&quot;&gt;# пояснение этой функции нам придётся отложить&lt;/font&gt;
   &lt;font color=&quot;#008000&quot;&gt;# до лучших времён&lt;/font&gt;
   &lt;font color=&quot;#a52a2a&quot;&gt;def&lt;/font&gt; set_optional_block(block)
       &lt;font color=&quot;#a52a2a&quot;&gt;if&lt;/font&gt; block.&lt;font color=&quot;#008080&quot;&gt;nil?&lt;/font&gt;
           [result=[], &lt;font color=&quot;#a52a2a&quot;&gt;lambda&lt;/font&gt; {|x| result &amp;lt;&amp;lt; x }]
       &lt;font color=&quot;#a52a2a&quot;&gt;else&lt;/font&gt;
           [nil, block]
       &lt;font color=&quot;#a52a2a&quot;&gt;end&lt;/font&gt;
   &lt;font color=&quot;#a52a2a&quot;&gt;end&lt;/font&gt;
       
   &lt;font color=&quot;#008000&quot;&gt;# перебрать все наборы с возможными повторениями&lt;/font&gt;
   &lt;font color=&quot;#a52a2a&quot;&gt;def&lt;/font&gt; tuples(&lt;font color=&quot;#008080&quot;&gt;size&lt;/font&gt;, &amp;amp;block)
       result,block = set_optional_block(block)
       tuples0(&lt;font color=&quot;#008080&quot;&gt;size&lt;/font&gt;,[],0,0,block)
       result
   &lt;font color=&quot;#a52a2a&quot;&gt;end&lt;/font&gt;
   
   &lt;font color=&quot;#008000&quot;&gt;# перебрать все наборы без повторений&lt;/font&gt;
   &lt;font color=&quot;#a52a2a&quot;&gt;def&lt;/font&gt; subsets(&lt;font color=&quot;#008080&quot;&gt;size&lt;/font&gt;, &amp;amp;block)
       result,block = set_optional_block(block)
       tuples0(&lt;font color=&quot;#008080&quot;&gt;size&lt;/font&gt;,[],0,1,block)
       result
   &lt;font color=&quot;#a52a2a&quot;&gt;end&lt;/font&gt;
       
   private
   &lt;font color=&quot;#008000&quot;&gt;# перебрать все наборы элементов при условии, что уже &lt;/font&gt;
   &lt;font color=&quot;#008000&quot;&gt;# набрана часть набора ary и нужно добрать элементов &lt;/font&gt;
   &lt;font color=&quot;#008000&quot;&gt;# из хвоста массива self[i..].&lt;/font&gt;
   &lt;font color=&quot;#008000&quot;&gt;# Повторения возможны, если norepeat = 0.&lt;/font&gt;
   &lt;font color=&quot;#a52a2a&quot;&gt;def&lt;/font&gt; tuples0(&lt;font color=&quot;#008080&quot;&gt;size&lt;/font&gt;,ary,i,norepeat,block)
       &lt;font color=&quot;#a52a2a&quot;&gt;if&lt;/font&gt; ary.&lt;font color=&quot;#008080&quot;&gt;size&lt;/font&gt; == &lt;font color=&quot;#008080&quot;&gt;size&lt;/font&gt;
           block[ary.&lt;font color=&quot;#008080&quot;&gt;dup&lt;/font&gt;] 
       &lt;font color=&quot;#a52a2a&quot;&gt;elsif&lt;/font&gt; i &amp;lt; &lt;font color=&quot;#a52a2a&quot;&gt;self&lt;/font&gt;.&lt;font color=&quot;#008080&quot;&gt;size&lt;/font&gt;
           &lt;font color=&quot;#008000&quot;&gt;# возьмем self[i]&lt;/font&gt;
           ary.&lt;font color=&quot;#008080&quot;&gt;push&lt;/font&gt; &lt;font color=&quot;#a52a2a&quot;&gt;self&lt;/font&gt;[i]
           tuples0(&lt;font color=&quot;#008080&quot;&gt;size&lt;/font&gt;,ary,i+norepeat,norepeat,block)
           ary.&lt;font color=&quot;#008080&quot;&gt;pop&lt;/font&gt;

           &lt;font color=&quot;#008000&quot;&gt;# или пропустим self[i]&lt;/font&gt;
           tuples0(&lt;font color=&quot;#008080&quot;&gt;size&lt;/font&gt;,ary,i+1,norepeat,block)
       &lt;font color=&quot;#a52a2a&quot;&gt;end&lt;/font&gt;
   &lt;font color=&quot;#a52a2a&quot;&gt;end&lt;/font&gt;

&lt;font color=&quot;#a52a2a&quot;&gt;end&lt;/font&gt;

&lt;font color=&quot;#008080&quot;&gt;puts&lt;/font&gt; &amp;quot;&lt;font color=&quot;#0000ff&quot;&gt;Волшебные тройки:&lt;/font&gt;&amp;quot;
&lt;font color=&quot;#008080&quot;&gt;puts&lt;/font&gt; (1..4).&lt;font color=&quot;#008080&quot;&gt;to_a&lt;/font&gt;.tuples(6).subsets(3).&lt;font color=&quot;#008080&quot;&gt;select&lt;/font&gt; { |t|
   ((t[0]&amp;lt;=&amp;gt;t[1]) + (t[1]&amp;lt;=&amp;gt;t[2]) + (t[2]&amp;lt;=&amp;gt;t[0])).&lt;font color=&quot;#008080&quot;&gt;abs&lt;/font&gt; == 3
}.&lt;font color=&quot;#008080&quot;&gt;inspect&lt;/font&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Данный код не намного короче кода на языке С++. Но заметьте, что приведённое здесь решения содержит определение функции &lt;code&gt;tuples&lt;/code&gt; и &lt;code&gt;subsets&lt;/code&gt;, которые могут быть использованы при решении многих других алгоритмических задач. Причём эти функции можно использовать с ассоциированным блоком или без, в зависимости от того, хоти те вы проитерировать наборы (&amp;quot;пробежаться&amp;quot; по ним), или хотите получить массив наборов. Задача была разбита на отдельные методы, так что само решение по сути, состоит из 4-х последних строчек кода.&lt;/p&gt;&lt;p&gt;Данный код можно существенно ускорить, если сделать кэширование значений сравнения:&lt;/p&gt;&lt;div class=&quot;fragment&quot;&gt;&lt;pre&gt;
    &lt;font color=&quot;#a52a2a&quot;&gt;def&lt;/font&gt; &amp;lt;=&amp;gt;(ary)
       @cache = &lt;a target=&quot;Hash&quot;&gt;Hash&lt;/a&gt;.&lt;font color=&quot;#008080&quot;&gt;new&lt;/font&gt; &lt;font color=&quot;#a52a2a&quot;&gt;if&lt;/font&gt; @cache.&lt;font color=&quot;#008080&quot;&gt;nil?&lt;/font&gt;
       &lt;font color=&quot;#a52a2a&quot;&gt;return&lt;/font&gt; @cache[ary] &lt;font color=&quot;#a52a2a&quot;&gt;if&lt;/font&gt; @cache.&lt;font color=&quot;#008080&quot;&gt;has_key?&lt;/font&gt;(ary)
       res = 0
       &lt;font color=&quot;#a52a2a&quot;&gt;self&lt;/font&gt;.&lt;font color=&quot;#008080&quot;&gt;each&lt;/font&gt; &lt;font color=&quot;#a52a2a&quot;&gt;do&lt;/font&gt; |x|
           ary.&lt;font color=&quot;#008080&quot;&gt;each&lt;/font&gt; &lt;font color=&quot;#a52a2a&quot;&gt;do&lt;/font&gt; |y|
               res += (x&amp;lt;=&amp;gt;y)
           &lt;font color=&quot;#a52a2a&quot;&gt;end&lt;/font&gt;
       &lt;font color=&quot;#a52a2a&quot;&gt;end&lt;/font&gt;
       @cache[ary]=(res &amp;lt;=&amp;gt; 0)
   &lt;font color=&quot;#a52a2a&quot;&gt;end&lt;/font&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Это кэширование позволяет уменьшить время поиска с 11,3 сек. до 2,7 сек. (на ноутбуке Pentium M, 1.7MHz). Для получения информации об использовании памяти и процессорного времени удобно использовать модуль benchmark:&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class=&quot;fragment&quot;&gt;&lt;pre&gt;&lt;font color=&quot;#a52a2a&quot;&gt;require&lt;/font&gt; &apos;&lt;font color=&quot;#0000ff&quot;&gt;benchmark&lt;/font&gt;&apos;
&lt;font color=&quot;#008080&quot;&gt;puts&lt;/font&gt; Benchmark.measure {
   &lt;font color=&quot;#008080&quot;&gt;puts&lt;/font&gt; [1,2,3,4].&lt;font color=&quot;#008080&quot;&gt;to_a&lt;/font&gt;.tuples(6).subsets(3).&lt;font color=&quot;#008080&quot;&gt;select&lt;/font&gt; { |t|
       ((t[0]&amp;lt;=&amp;gt;t[1]) + (t[1]&amp;lt;=&amp;gt;t[2]) + (t[2]&amp;lt;=&amp;gt;t[0])).&lt;font color=&quot;#008080&quot;&gt;abs&lt;/font&gt; == 3
   }.&lt;font color=&quot;#008080&quot;&gt;size&lt;/font&gt;
}&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Данный код напечатает число найденных волшебных троек (43, досадно, что не 42) и время, потраченное на вычисления: процессорное время, потраченное на пользовательский код, процессорное время, потраченное на выполнение системных вызовов и реальное время, которое прошло, пока вычислялся заданный блок.&lt;/p&gt;&lt;p&gt;Документацию по различным классам и их методам можно получить, используя графическое приложение fxri, включенное в дистрибутив Ruby под Windows.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h2&gt;&lt;a name=&quot;_o__cm_g&quot;&gt;&lt;/a&gt;См. также&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a target=&quot;_top&quot; href=&quot;http://ru.wikibooks.org/wiki/Ruby&quot;&gt;http://ru.wikibooks.org/wiki/Ruby&lt;/a&gt; - книжка про Ruby на русском языке.&lt;/li&gt;&lt;li&gt;&lt;a target=&quot;_top&quot; href=&quot;http://acm.mipt.ru/bin/view/Ruby&quot;&gt;http://acm.mipt.ru/bin/view/Ruby&lt;/a&gt; - учебные материалы на сайте МФТИ.&lt;/li&gt;&lt;li&gt;Programming Ruby, Dave Thomas with Chad Fowler and Andy Hunt (Программирование на Ruby, Дейв Томас, совместно с Чадом Фоулером и Энди Хантом)&lt;/li&gt;&lt;li&gt;Agile Web Development with Rails - Pragmatic Programmers Guide, Dave Thomas (Гибкое программирование под Web на Rails, Дейв Томас)&lt;/li&gt;&lt;/ul&gt;</description>
  <comments>http://artemvoroztsov.livejournal.com/528.html</comments>
  <category>algorithms</category>
  <category>ruby</category>
  <category>education</category>
  <lj:music>Transoceanic</lj:music>
  <media:title type="plain">Transoceanic</media:title>
  <lj:mood>creative</lj:mood>
  <lj:security>public</lj:security>
  <lj:reply-count>6</lj:reply-count>
</item>
<item>
  <guid isPermaLink='true'>http://artemvoroztsov.livejournal.com/482.html</guid>
  <pubDate>Wed, 30 May 2007 19:52:12 GMT</pubDate>
  <title>Уроки Ruby. Быстрая сортировка.</title>
  <link>http://artemvoroztsov.livejournal.com/482.html</link>
  <description>&lt;h1&gt;&lt;font size=&quot;3&quot;&gt;См. теорию на &lt;/font&gt;&lt;a href=&quot;http://acm.mipt.ru/twiki/bin/view/Algorithms/QuickSort&quot;&gt;&lt;font size=&quot;3&quot;&gt;Algorithms.QuickSort&lt;/font&gt;&lt;/a&gt; &lt;/h1&gt;&lt;p&gt;Конечно на практике нужно пользоваться методами &lt;code&gt;sort&lt;/code&gt; и &lt;code&gt;sort!&lt;/code&gt;, определенными для всех стандартных контейнеров. Эти функции возвращают массив. &lt;/p&gt;&lt;p&gt;В учебных целях реализуем алгоритм быстрой сортировки на самом Ruby. &lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h2&gt;&lt;a name=&quot;_g_qf_1&quot;&gt;&lt;/a&gt;Метод 1 &lt;/h2&gt;&lt;p&gt;Попробуем использовать метод &lt;code&gt;partition&lt;/code&gt;, определенный для экземпляров &lt;code&gt;Enumerable&lt;/code&gt;: &lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class=&quot;fragment&quot;&gt;&lt;pre&gt;&lt;font color=&quot;#a52a2a&quot;&gt;class&lt;/font&gt; &lt;a target=&quot;Array&quot;&gt;Array&lt;/a&gt; &lt;br /&gt;   &lt;font color=&quot;#a52a2a&quot;&gt;def&lt;/font&gt; qsort&lt;br /&gt;      &lt;font color=&quot;#a52a2a&quot;&gt;return&lt;/font&gt; &lt;font color=&quot;#a52a2a&quot;&gt;self&lt;/font&gt;.&lt;font color=&quot;#008080&quot;&gt;dup&lt;/font&gt; &lt;font color=&quot;#a52a2a&quot;&gt;if&lt;/font&gt; &lt;font color=&quot;#008080&quot;&gt;size&lt;/font&gt; &amp;lt;=1&lt;br /&gt;      e = &lt;font color=&quot;#a52a2a&quot;&gt;self&lt;/font&gt;.&lt;font color=&quot;#008080&quot;&gt;first&lt;/font&gt; &lt;font color=&quot;#008000&quot;&gt;# делить будем по первому элементу&lt;/font&gt;&lt;br /&gt;      l,r = partition   {|x| x &amp;lt;= e}&lt;br /&gt;      a,l = l.partition {|x| x == e}&lt;br /&gt;      l.qsort + a + r.qsort &lt;font color=&quot;#008000&quot;&gt;# конкатенация трех массивов&lt;/font&gt;&lt;br /&gt;   &lt;font color=&quot;#a52a2a&quot;&gt;end&lt;/font&gt;&lt;br /&gt;&lt;font color=&quot;#a52a2a&quot;&gt;end&lt;/font&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h2&gt;&lt;a name=&quot;_g_qf_2&quot;&gt;&lt;/a&gt;Метод 2 &lt;/h2&gt;&lt;p&gt;Но удобно делить исходный массив сразу на три массива. Для этого определим метод &lt;code&gt;partition3&lt;/code&gt;: &lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class=&quot;fragment&quot;&gt;&lt;pre&gt;&lt;font color=&quot;#a52a2a&quot;&gt;class&lt;/font&gt; &lt;a target=&quot;Array&quot;&gt;Array&lt;/a&gt; &lt;br /&gt;   &lt;font color=&quot;#008000&quot;&gt;# given block should return 0,1 or 2&lt;/font&gt;&lt;br /&gt;   &lt;font color=&quot;#008000&quot;&gt;# -1 stands for 2&lt;/font&gt;&lt;br /&gt;   &lt;font color=&quot;#008000&quot;&gt;# outputs three arrays&lt;/font&gt;&lt;br /&gt;   &lt;font color=&quot;#a52a2a&quot;&gt;def&lt;/font&gt; partition3&lt;br /&gt;      a = &lt;a target=&quot;Array&quot;&gt;Array&lt;/a&gt;.&lt;font color=&quot;#008080&quot;&gt;new&lt;/font&gt;(3) {|i| []}&lt;br /&gt;      &lt;font color=&quot;#008080&quot;&gt;each&lt;/font&gt; &lt;font color=&quot;#a52a2a&quot;&gt;do&lt;/font&gt; |x|&lt;br /&gt;         a[&lt;font color=&quot;#a52a2a&quot;&gt;yield&lt;/font&gt;(x)].&lt;font color=&quot;#008080&quot;&gt;push&lt;/font&gt; x&lt;br /&gt;      &lt;font color=&quot;#a52a2a&quot;&gt;end&lt;/font&gt;&lt;br /&gt;      a&lt;br /&gt;   &lt;font color=&quot;#a52a2a&quot;&gt;end&lt;/font&gt;&lt;br /&gt;   &lt;font color=&quot;#a52a2a&quot;&gt;def&lt;/font&gt; qsort&lt;br /&gt;      &lt;font color=&quot;#a52a2a&quot;&gt;return&lt;/font&gt; &lt;font color=&quot;#a52a2a&quot;&gt;self&lt;/font&gt;.&lt;font color=&quot;#008080&quot;&gt;dup&lt;/font&gt; &lt;font color=&quot;#a52a2a&quot;&gt;if&lt;/font&gt; &lt;font color=&quot;#008080&quot;&gt;size&lt;/font&gt; &amp;lt;=1&lt;br /&gt;      a,l,r = partition3 {|x| &lt;font color=&quot;#008080&quot;&gt;first&lt;/font&gt; &amp;lt;=&amp;gt; x}&lt;br /&gt;      l.qsort + a +  r.qsort&lt;br /&gt;   &lt;font color=&quot;#a52a2a&quot;&gt;end&lt;/font&gt;&lt;br /&gt;&lt;font color=&quot;#a52a2a&quot;&gt;end&lt;/font&gt;   &lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Можно сделать более универсальную функцию &lt;code&gt;partitionN&lt;/code&gt; &lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class=&quot;fragment&quot;&gt;&lt;pre&gt;&lt;font color=&quot;#a52a2a&quot;&gt;class&lt;/font&gt; &lt;a target=&quot;Array&quot;&gt;Array&lt;/a&gt;&lt;br /&gt;   &lt;font color=&quot;#a52a2a&quot;&gt;def&lt;/font&gt; partitionN&lt;br /&gt;      &lt;font color=&quot;#008080&quot;&gt;inject&lt;/font&gt;(&lt;a target=&quot;Hash&quot;&gt;Hash&lt;/a&gt;.&lt;font color=&quot;#008080&quot;&gt;new&lt;/font&gt;) { |f,x|&lt;br /&gt;         key = &lt;font color=&quot;#a52a2a&quot;&gt;yield&lt;/font&gt;(x)&lt;br /&gt;         f[key]=[] &lt;font color=&quot;#a52a2a&quot;&gt;unless&lt;/font&gt; f.&lt;font color=&quot;#008080&quot;&gt;has_key?&lt;/font&gt;(key)&lt;br /&gt;         f[key].&lt;font color=&quot;#008080&quot;&gt;push&lt;/font&gt; x&lt;br /&gt;         f&lt;br /&gt;      }.&lt;font color=&quot;#008080&quot;&gt;to_a&lt;/font&gt;.&lt;font color=&quot;#008080&quot;&gt;sort&lt;/font&gt;.&lt;font color=&quot;#008080&quot;&gt;map&lt;/font&gt;{|pair| pair[1]}&lt;br /&gt;   &lt;font color=&quot;#a52a2a&quot;&gt;end&lt;/font&gt;&lt;br /&gt;&lt;font color=&quot;#a52a2a&quot;&gt;end&lt;/font&gt;&lt;br /&gt;p [0,1,2,3,5,4,3,6,7,5,4,3,4,65,7,87,4523].partitionN {|x| x % 4}&lt;br /&gt;&lt;font color=&quot;#008000&quot;&gt;#&lt;/font&gt;&lt;br /&gt;&lt;font color=&quot;#008000&quot;&gt;# =&amp;gt; [[0, 4, 4, 4], [1, 5, 5, 65], [2, 6], [3, 3, 7, 3, 7, 87, 4523]]&lt;/font&gt;&lt;br /&gt;&lt;font color=&quot;#008000&quot;&gt;#&lt;/font&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h2&gt;&lt;a name=&quot;_gcnk_ceks_qsort_tt_&quot;&gt;&lt;/a&gt;Реализация &lt;tt&gt;qsort!&lt;/tt&gt; &lt;/h2&gt;&lt;p&gt;Необходима также версия функции сортировки, которая сортирует массив &quot;на месте&quot;. Вот она: &lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class=&quot;fragment&quot;&gt;&lt;pre&gt;&lt;font color=&quot;#a52a2a&quot;&gt;class&lt;/font&gt; &lt;a target=&quot;Array&quot;&gt;Array&lt;/a&gt;&lt;br /&gt;   &lt;font color=&quot;#a52a2a&quot;&gt;def&lt;/font&gt; qsort!&lt;br /&gt;      &lt;font color=&quot;#a52a2a&quot;&gt;self&lt;/font&gt;.replace(&lt;font color=&quot;#a52a2a&quot;&gt;self&lt;/font&gt;.qsort)&lt;br /&gt;   &lt;font color=&quot;#a52a2a&quot;&gt;end&lt;/font&gt;&lt;br /&gt;&lt;font color=&quot;#a52a2a&quot;&gt;end&lt;/font&gt;&lt;br /&gt;a = [1,7,6,5,4,3,2,1]&lt;br /&gt;a.qsort!&lt;br /&gt;p a&lt;br /&gt;&lt;font color=&quot;#008000&quot;&gt;#&lt;/font&gt;&lt;br /&gt;&lt;font color=&quot;#008000&quot;&gt;# =&amp;gt; [1, 1, 2, 3, 4, 5, 6, 7]&lt;/font&gt;&lt;br /&gt;&lt;font color=&quot;#008000&quot;&gt;#&lt;/font&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;h2&gt;&lt;a name=&quot;_g_qf__q_fc__kl_og_qf__oqfkhkmc_&quot;&gt;&lt;/a&gt;Метод, создающий методы-модификаторы &lt;/h2&gt;&lt;p&gt;Целый ряд методов в стандартных классах Ruby имеет аналоги, модифицирующие сам объект. Имена этих функций заканчиваются на &lt;code&gt;!&lt;/code&gt;, например, &lt;code&gt;sort!&lt;/code&gt;, &lt;code&gt;uniq!&lt;/code&gt;, &lt;code&gt;map!&lt;/code&gt;. &lt;/p&gt;&lt;p&gt;Их все можно было определить разом. Например так: &lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class=&quot;fragment&quot;&gt;&lt;pre&gt;&lt;font color=&quot;#a52a2a&quot;&gt;def&lt;/font&gt; make_modifiers(*&lt;font color=&quot;#008080&quot;&gt;methods&lt;/font&gt;)&lt;br /&gt;   &lt;font color=&quot;#008080&quot;&gt;methods&lt;/font&gt;.&lt;font color=&quot;#008080&quot;&gt;each&lt;/font&gt; &lt;font color=&quot;#a52a2a&quot;&gt;do&lt;/font&gt; |&lt;font color=&quot;#008080&quot;&gt;method&lt;/font&gt;|&lt;br /&gt;      eval &quot;&lt;font color=&quot;#0000ff&quot;&gt; &lt;br /&gt;         class #{self.to_s}&lt;br /&gt;            def #{method}!(*args,&amp;amp;block)&lt;br /&gt;               self.replace(self.#{method}(*args,&amp;amp;block))&lt;br /&gt;            end&lt;br /&gt;         end&lt;br /&gt;      &lt;/font&gt;&quot;&lt;br /&gt;   &lt;font color=&quot;#a52a2a&quot;&gt;end&lt;/font&gt;&lt;br /&gt;&lt;font color=&quot;#a52a2a&quot;&gt;end&lt;/font&gt;&lt;br /&gt;&lt;font color=&quot;#a52a2a&quot;&gt;class&lt;/font&gt; &lt;a target=&quot;Array&quot;&gt;Array&lt;/a&gt;&lt;br /&gt;   make_modifiers :sort, :uniq, :map&lt;br /&gt;&lt;font color=&quot;#a52a2a&quot;&gt;end&lt;/font&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Из соображений оптимизации такие вещи не делаются для ключевых функций (из соображений оптимизации многие методы стандартных классов реализованы на Си). Но в принципе, это очень правильная идея — можно и нужно использовать средства метапрограммирования для упрощения кода и уменьшения труда программиста. &lt;/p&gt;</description>
  <comments>http://artemvoroztsov.livejournal.com/482.html</comments>
  <category>algorithms</category>
  <category>ruby</category>
  <category>education</category>
  <lj:music>Naomi</lj:music>
  <media:title type="plain">Naomi</media:title>
  <lj:mood>creative</lj:mood>
  <lj:security>public</lj:security>
  <lj:reply-count>2</lj:reply-count>
</item>
</channel>
</rss>
