<?xml version="1.0" encoding="utf-8" ?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:tt="http://teletype.in/" xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/"><title>Сергей Мелюков</title><subtitle>Software Architect</subtitle><author><name>Сергей Мелюков</name></author><id>https://teletype.in/atom/smelukov_dev</id><link rel="self" type="application/atom+xml" href="https://teletype.in/atom/smelukov_dev?offset=0"></link><link rel="alternate" type="text/html" href="https://teletype.in/@smelukov_dev?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=smelukov_dev"></link><link rel="next" type="application/rss+xml" href="https://teletype.in/atom/smelukov_dev?offset=10"></link><link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></link><updated>2026-07-31T09:09:16.848Z</updated><entry><id>smelukov_dev:codewars-square-every-digit</id><link rel="alternate" type="text/html" href="https://teletype.in/@smelukov_dev/codewars-square-every-digit?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=smelukov_dev"></link><title>codewars: square every digit</title><published>2021-03-02T23:22:36.339Z</published><updated>2021-03-03T11:31:35.089Z</updated><category term="codewars" label="Codewars"></category><tt:hashtag>codewars</tt:hashtag><tt:hashtag>js</tt:hashtag><tt:hashtag>javascript</tt:hashtag><tt:hashtag>решениезадач</tt:hashtag><tt:hashtag>алгоритмы</tt:hashtag><summary type="html">⚠️ Статья наполнена спойлерами. Если вы хотите сами решить задачу, то вернитесь к статье только после того как решите ее сами или если у вас закончится терпение 😉</summary><content type="html">
  &lt;blockquote&gt;⚠️ Статья наполнена спойлерами. Если вы хотите сами решить задачу, то вернитесь к статье только после того как решите ее сами или если у вас закончится терпение 😉&lt;/blockquote&gt;
  &lt;p&gt;Недавно я откапал свой логин/пароль к &lt;a href=&quot;https://www.codewars.com/dashboard&quot; target=&quot;_blank&quot;&gt;codewars&lt;/a&gt; и наткнулся на &lt;a href=&quot;https://www.codewars.com/kata/546e2562b03326a88e000020&quot; target=&quot;_blank&quot;&gt;задачку&lt;/a&gt; с таким описанием:&lt;/p&gt;
  &lt;pre&gt;You are asked to square every digit of a number and concatenate them.
For example, if we run 9119 through the function, 811181 will come out, because 9^2 is 81 and 1^2 is 1.
Note: The function accepts an integer and returns an integer&lt;/pre&gt;
  &lt;p&gt;Смысл в том, что на вход функции поступает число, каждый разряд которого нужно возвести в квадрат. Полученные квадраты разрядов нужно объединить и вернуть из функции.&lt;/p&gt;
  &lt;p&gt;На входе и на выходе должны быть именно числа (&lt;code&gt;typeof x === &amp;#x27;number&amp;#x27;&lt;/code&gt;). Примеры:&lt;/p&gt;
  &lt;pre&gt;fn(3212) // 9414
fn(9119) //811181&lt;/pre&gt;
  &lt;p&gt;Я решил задачку по-своему - так, как считал оптимальным, затем посмотрел как решили другие, сделал определенные выводы, которые показались мне интересными. Затем &lt;a href=&quot;https://t.me/smelukov_dev/81&quot; target=&quot;_blank&quot;&gt;задал вопрос&lt;/a&gt; подписчикам моего telegram-канала - как они решили бы эту задачу. Собрал варианты, которые они предложили, сгруппировал их, и в этой статье хочу сравнить их. Все решения будем сравнивать относительно моего (его приведу ближе к концу).&lt;/p&gt;
  &lt;blockquote&gt;Замеры я производил на основе 1,000,000 заранее сгенерированных чисел от 0 до 1,000,000&lt;/blockquote&gt;
  &lt;p&gt;Итак. Конечно же, первое, что приходит в голову - это решение при помощи строк. Оно просто и короткое:&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;превратили число в строку&lt;/li&gt;
    &lt;li&gt;смапили символы-разряды на их квадраты&lt;/li&gt;
    &lt;li&gt;соединили&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p&gt;Но здесь не все так однозначно и решение на строках может быть разным.&lt;/p&gt;
  &lt;p&gt;Рассмотрим пример:&lt;/p&gt;
  &lt;pre&gt;const fn = val =&amp;gt; +[...&amp;#x27;&amp;#x27; + val].map(n =&amp;gt; n ** 2).join(&amp;#x27;&amp;#x27;);&lt;/pre&gt;
  &lt;p&gt;Это простое решение не эффективно с точки зрения утилизации ресурсов. &lt;/p&gt;
  &lt;p&gt;Здесь мы делаем много лишних действий:&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;преобразуем число в строку&lt;/li&gt;
    &lt;li&gt;преобразуем строку в массив&lt;/li&gt;
    &lt;li&gt;каждый символ строки преобразуем в число (&lt;code&gt;n ** 2&lt;/code&gt;)&lt;/li&gt;
    &lt;li&gt;преобразуем получившийся массив в строку&lt;/li&gt;
    &lt;li&gt;преобразуем получившуюся строку в число&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p&gt;Этот вариант в 6.9 медленнее эталона 📉&lt;/p&gt;
  &lt;p&gt;Из этого делаем вывод, что преобразования - это плохо для производительности и нам нужно постараться свести их к минимуму.&lt;/p&gt;
  &lt;p&gt;Попробуем еще одно решение на строках, но с меньшим количеством преобразований:&lt;/p&gt;
  &lt;pre&gt;function fn(val) {
  let res = &amp;#x27;&amp;#x27;;
  val = val + &amp;#x27;&amp;#x27;;
  
  for (let i = 0; i &amp;lt; val.length; i++) {
    res += val[i] ** 2;
  }
  
  return +res;
}&lt;/pre&gt;
  &lt;ul&gt;
    &lt;li&gt;преобразуем число в строку (&lt;code&gt;val + &amp;#x27;&amp;#x27;&lt;/code&gt;)&lt;/li&gt;
    &lt;li&gt;преобразуем каждый символ в число и обратно (&lt;code&gt;res += val[i] ** 2&lt;/code&gt;)&lt;/li&gt;
    &lt;li&gt;преобразуем строку в число (&lt;code&gt;+res&lt;/code&gt;)&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p&gt;Этот вариант уже в 3.6 раза медленнее эталона 📉&lt;/p&gt;
  &lt;p&gt;&lt;a href=&quot;https://twitter.com/rdvornov&quot; target=&quot;_blank&quot;&gt;Роман Дворнов&lt;/a&gt; предложил интересное решение&lt;/p&gt;
  &lt;pre&gt;function fn(val) {
  return +String(val).replace(/./g, m =&amp;gt; m * m);
}&lt;/pre&gt;
  &lt;p&gt;Здесь мы используем замену по регулярному выражению, чтобы заменить все числа на их квадраты. Не смотря на небольшое количество преобразований, оно в 10.9 раз медленнее эталона из-за регулярных выражений 📉&lt;/p&gt;
  &lt;p&gt;Так же Роман предложил развитие идеи:&lt;/p&gt;
  &lt;pre&gt;const xs = [&amp;quot;0&amp;quot;, &amp;quot;1&amp;quot;, &amp;quot;4&amp;quot;, &amp;quot;9&amp;quot;, &amp;quot;16&amp;quot;, &amp;quot;25&amp;quot;, &amp;quot;36&amp;quot;, &amp;quot;49&amp;quot;, &amp;quot;64&amp;quot;, &amp;quot;81&amp;quot;];

function fn(val) {
  return +String(val).replace(/[2-9]/g, m =&amp;gt; xs[m]);
}&lt;/pre&gt;
  &lt;p&gt;Суть в том, что мы заранее высчитываем квадраты чисел от 0 до 9 и записываем их в массив в виде &lt;strong&gt;строк&lt;/strong&gt; (это важно!).&lt;/p&gt;
  &lt;p&gt;В самой функции мы заменяем числа от 2 до 9 на их предрассчитанные значения из массива. Единицы и нули не имеет смысла заменять, т.к. они останутся без изменений в какую бы степень мы их не возвели.&lt;/p&gt;
  &lt;p&gt;Предрассчитанные квадраты чисел хранятся в массиве в виде строк чтобы при замене не было приведения числа к строке.&lt;/p&gt;
  &lt;p&gt;Этот вариант в 9.8 раз медленнеее эталона 📉&lt;/p&gt;
  &lt;p&gt;Не смотря на низкую производительность, мы вернемся к этому варианту позже.&lt;/p&gt;
  &lt;p&gt;Очевидно, что преобразования на строках - это не лучшее решение с точки зрения производительности.&lt;/p&gt;
  &lt;p&gt;Если важна скорость и что-то можно сделать при помощи математики, то лучше деать это при помощи математики.&lt;/p&gt;
  &lt;p&gt;Возьмем для примера число &lt;code&gt;3212&lt;/code&gt;, оно должно превратиться в &lt;code&gt;9414&lt;/code&gt;.&lt;/p&gt;
  &lt;p&gt;&lt;strong&gt;Как можно проделать с ним все нужные нам операции без пробразований?&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt;Число можно разделить на разряды:&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;9 - разряд тысяч&lt;/li&gt;
    &lt;li&gt;4 - разряд сотен&lt;/li&gt;
    &lt;li&gt;1 - разряд десятков&lt;/li&gt;
    &lt;li&gt;4 - разряд единиц&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p&gt;&lt;strong&gt;Как собрать число имея каждый разряд по отдельности?&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt;Необходимо найти сумму произведений каждого разряда на значение этого разряда. Проще говоря:&lt;/p&gt;
  &lt;pre&gt;9414 = (4 * 1) + (1 * 10) + (4 * 100) + (9 * 1000)&lt;/pre&gt;
  &lt;p&gt;&lt;strong&gt;Как получить то же самое из числа 3212?&lt;/strong&gt;&lt;/p&gt;
  &lt;pre&gt;9414 = (2^2 * 1) + (1^2 * 10) + (2^2 * 100) + (3^2 * 1000)&lt;/pre&gt;
  &lt;p&gt;&lt;strong&gt;Как реализовать это в виде кода?&lt;/strong&gt;&lt;/p&gt;
  &lt;pre&gt;function fn(num) {
  let multiplier = 1;
  let res = 0;
  
  while (num !== 0) {
    const digit = num % 10;
    const sqr = digit ** 2;
    
    num = ~~(num / 10);
    res += sqr * multiplier;
    multiplier *= (sqr &amp;lt; 10 ? 10 : 100);
  }
  
  return res;
}&lt;/pre&gt;
  &lt;blockquote&gt;Если у вас есть вопросы по логике кода, пожалуйста, пишите в комменты.&lt;/blockquote&gt;
  &lt;p&gt;Подписчики предлагали похожие решения, например:&lt;/p&gt;
  &lt;pre&gt;function fn(n) {
  let pow = 0;
  const getNum = () =&amp;gt; {
    let res = Math.floor(n / (10 ** pow));
    return res &amp;gt; 0 ? res % 10 : 0;
  }
  
  let num;
  let result = 0;
  let resultPow = 0;
  
  while ((num = getNum()) &amp;gt; 0) {
    result += (num * num) * (10 ** resultPow);
    resultPow += (num &amp;gt; 3) ? 2 : 1;
    pow++;
  }
  
  return result;
}&lt;/pre&gt;
  &lt;p&gt;Но не смотря на то, что здесь нет преобразований, этот вариант в 6.2 раз медленнее эталона и в 1.7 раз медленне оптимального варианта со строками 📉. Это позволяет сделать вывод, что наличие большого количества операций и вызова функций (добавляют манипуляций со стеком) может нивелировать профит от отсутствия преобразований.&lt;/p&gt;
  &lt;p&gt;Ближе всего к моему варианту был такой пример:&lt;/p&gt;
  &lt;pre&gt;function fn6(number) {
  let result = 0;
  let signs = 1;
  
  while (number &amp;gt; 0) {
    let digit = number % 10;
    
    result += digit * digit * signs;
    signs *= digit &amp;gt; 3 ? 100 : 10;
    number = Math.floor(number / 10);
  }
  
  return result;
}&lt;/pre&gt;
  &lt;p&gt;Он всего на 10% медленнее моего . Но за счет чего?&lt;/p&gt;
  &lt;p&gt;Дело в том, что &lt;code&gt;Math.floor&lt;/code&gt; - это &lt;a href=&quot;https://262.ecma-international.org/6.0/#sec-math.floor&quot; target=&quot;_blank&quot;&gt;дополнительная логика под капотом&lt;/a&gt; и если заменить &lt;code&gt;Math.floor(number / 10)&lt;/code&gt; на &lt;code&gt;~~(number / 10)&lt;/code&gt;  то мы получим ту же производительность.&lt;/p&gt;
  &lt;h2&gt;Бонус&lt;/h2&gt;
  &lt;p&gt;А теперь давайте вернемся к варианту, который предлагал Роман Дворнов и позаимствуем оттуда идею с предрассчитанными квадратами, объединим с моим вариантом и получим более производительную функцию:&lt;/p&gt;
  &lt;pre&gt;const xn = [0, 1, 4, 9, 16, 25, 36, 49, 64, 81];

function fn(num) {
  let multiplier = 1;
  let res = 0;
  
  while (num !==0) {
    const digit = num % 10;
    
    num = ~~(num / 10);
    res += xn[digit] * multiplier;
    multiplier *= (num &amp;lt; 4 ? 10 : 100);
  }
  
  return res;
}&lt;/pre&gt;
  &lt;p&gt;Этот вариант на ~13% быстрее моего изначального варианта за счет того, что мы избавились от математической операции 📈&lt;/p&gt;
  &lt;p&gt;Ну а позже Роман предложил еще один вариант, до которого у меня самого дошли только мысли, но не руки - заменить часть ариметики на побитовые операции:&lt;/p&gt;
  &lt;pre&gt;const xn = [0, 1, 4, 9, 16, 25, 36, 49, 64, 81];

function fn(num){
  let multiplier = 1;
  let res = 0;
  
  while(true) {
    const digit = num % 10;
    
    res += xn[digit] * multiplier;
    
    if (num === digit) break;
    
    num = ~~(num / 10);
    multiplier = digit &amp;lt; 4 ? 
      (multiplier &amp;lt;&amp;lt; 3) + (multiplier &amp;lt;&amp;lt; 1) :
      (multiplier &amp;lt;&amp;lt; 6) + (multiplier &amp;lt;&amp;lt; 5) + (multiplier &amp;lt;&amp;lt; 2);
  }
  
  return res;
}&lt;/pre&gt;
  &lt;p&gt;Плюс ко всему, за счет &lt;code&gt;break&lt;/code&gt;, мы можем не высчитывать &lt;code&gt;num&lt;/code&gt; и &lt;code&gt;multiplier&lt;/code&gt; на последней итерации.&lt;/p&gt;
  &lt;p&gt;Хотя такой код и труднее читать, он на ~20% быстрее моего изначального варианта 📈&lt;/p&gt;
  &lt;h2&gt;Подводя итог&lt;/h2&gt;
  &lt;p&gt;К сожалению, JS в какой-то степени расслабляет и часто мы пишем простой, но не производительный код.&lt;/p&gt;
  &lt;p&gt;Если вашему коду жизненно важна производительность, то ее надо буквально &amp;quot;выгрызать&amp;quot; любыми доступными способами, экономя любые операции. Но если нужно просто написать производительный код, то пишите его так, чтобы не было лишних операций и тем более ненужных преобразований. Соблюдайте баланс между производительностью и читаемостью.&lt;/p&gt;
  &lt;tt-tags&gt;
    &lt;tt-tag name=&quot;codewars&quot;&gt;#codewars&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;js&quot;&gt;#js&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;javascript&quot;&gt;#javascript&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;решениезадач&quot;&gt;#решениезадач&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;алгоритмы&quot;&gt;#алгоритмы&lt;/tt-tag&gt;
  &lt;/tt-tags&gt;

</content></entry><entry><id>smelukov_dev:rt-count-on-me</id><link rel="alternate" type="text/html" href="https://teletype.in/@smelukov_dev/rt-count-on-me?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=smelukov_dev"></link><title>return true: countOnMe</title><published>2021-02-28T20:23:12.428Z</published><updated>2021-03-01T08:39:13.558Z</updated><category term="return-true" label="return true"></category><tt:hashtag>returntrue</tt:hashtag><tt:hashtag>js</tt:hashtag><tt:hashtag>javascript</tt:hashtag><summary type="html">Привет! Сегодня разбираемся с задачкой countOnMe из второго сезона RT.</summary><content type="html">
  &lt;p&gt;Привет! Сегодня разбираемся с задачкой &lt;code&gt;countOnMe&lt;/code&gt; из второго сезона &lt;a href=&quot;https://alf.nu/ReturnTrue&quot; target=&quot;_blank&quot;&gt;RT&lt;/a&gt;.&lt;/p&gt;
  &lt;blockquote&gt;⚠️ Статья наполнена спойлерами. Если вы хотите сами решить задачу, то вернитесь к статье только после того как решите ее сами или если у вас закончится терпение 😉&lt;/blockquote&gt;
  &lt;h2&gt;countOnMe1&lt;/h2&gt;
  &lt;pre&gt;function countOnMe(x) {
  if (!(x instanceof Array))
    throw &amp;#x27;x must be an array.&amp;#x27;;

  for (var i = 0; i &amp;lt; 20; i++) {
    if (x[i] != i) {
      throw &amp;#x27;x must contain the numbers 0-19 in order&amp;#x27;;
    }
  }

  return true;
}&lt;/pre&gt;
  &lt;p&gt;Задача в том, чтобы передать в функцию массив, состоящий из цифр от 0 до 19.&lt;/p&gt;
  &lt;p&gt;Конечно, можно просто передать &lt;code&gt;[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19]&lt;/code&gt;, но это было бы слишком просто и очевидность этого решения намекает на то, что есть решение короче 51 байта.&lt;/p&gt;
  &lt;p&gt;Наша задача сделать так, чтобы условие &lt;code&gt;x[i] != i&lt;/code&gt; никогда не выполнялось.&lt;/p&gt;
  &lt;p&gt;Можно попробовать создать &lt;code&gt;Proxy&lt;/code&gt;, который будет перехватывать все попытки обратиться к какому-либо свойству и возвращать обратно имя свойства:&lt;/p&gt;
  &lt;pre&gt;const x = new Proxy([], {
  get: (target, key) =&amp;gt; key
});
x[1] // &amp;#x27;1&amp;#x27;
x[100] // &amp;#x27;100&amp;#x27;
x[&amp;#x27;hi&amp;#x27;] // &amp;#x27;hi&amp;#x27;&lt;/pre&gt;
  &lt;p&gt;Таким образом, не важно сколько у нас элементов в массиве, на все попытки обратиться к элементу по индексу, мы будем возвращать этот индекс обратно. В итоге, используя &lt;code&gt;new Proxy([],{get:(t,k)=&amp;gt;k})&lt;/code&gt;, мы получаем &lt;code&gt;true&lt;/code&gt; за 28 байт ✅&lt;/p&gt;
  &lt;blockquote&gt;Мы считаем именно байты, а не символы. Так например, один символ эмодзи будет занимать несколько байт (от 2 и более)&lt;/blockquote&gt;
  &lt;p&gt;Видим в лидерборде, что лучшее решение - это 18 байт, поэтому думаем как можно сократить решение.&lt;/p&gt;
  &lt;p&gt;Еще один вариант решения основан на том, что мы можем сгенерировать массив указанной длины: &lt;code&gt;Array(20)&lt;/code&gt;&lt;/p&gt;
  &lt;p&gt;Но это пустой массив, поэтому он не пройдет все проверки. Тем не менее, из этого массива мы можем получить ключи:&lt;/p&gt;
  &lt;pre&gt;const keys = [...Array(20).keys()];
keys // [0,1,2,...,17,18,19]&lt;/pre&gt;
  &lt;p&gt;Используем spread-оператор потому что &lt;code&gt;Array#keys()&lt;/code&gt; возвращает не массив, а итерируемый объект.&lt;/p&gt;
  &lt;p&gt;Получаем &lt;code&gt;true&lt;/code&gt; за 21 байт ✅, но это все еще не 18, поэтому думаем дальше.&lt;/p&gt;
  &lt;p&gt;&lt;strong&gt;Как еще можно получить массив из 20 элементов?&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt;Можно применить подход с получением ключей, но будем получать не ключи массива, а ключи строки:&lt;/p&gt;
  &lt;pre&gt;const keys = Object.keys(&amp;#x27;это строка в 20 байт&amp;#x27;);
keys // [0,1,2,...,17,18,19]&lt;/pre&gt;
  &lt;p&gt;Теперь нам осталось понять как сгенерировать строку длиной минимум в 20 байт (можно и больше, просто в задаче проверяются только первые 20). Вот варианты того, как это можно сделать:&lt;/p&gt;
  &lt;pre&gt;Object.keys(9**-9+&amp;#x27;&amp;#x27;) // решение в 21 байт ✅
Object.keys(9e19+&amp;#x27;&amp;#x27;) // решение в 20 байт ✅
Object.keys(Date()) // решение в 19 байт ✅&lt;/pre&gt;
  &lt;p&gt;Но 19 байт это все еще не 18.&lt;/p&gt;
  &lt;p&gt;Давайте вспомним про преобразование типов, которое мы &lt;a href=&quot;https://teletype.in/@smelukov_dev/rt-length&quot; target=&quot;_blank&quot;&gt;применили для решения задачи length&lt;/a&gt; и используем его снова: &lt;/p&gt;
  &lt;pre&gt;Set+1 // &amp;#x27;function Set() { [native code] }&amp;#x27;
Object.keys(Set+1) // [0,1,2,3,...,29,30,31,32]&lt;/pre&gt;
  &lt;p&gt;Это и есть решение в 18 байт ✅&lt;/p&gt;
  &lt;h3&gt;Решения&lt;/h3&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;code&gt;[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19]&lt;/code&gt; - 51&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;new Proxy([],{get:(i,k)=&amp;gt;k})&lt;/code&gt; - 28&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;[…Array(20).keys()]&lt;/code&gt; - 21&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;Object.keys(9**-9+&amp;#x27;&amp;#x27;)&lt;/code&gt; - 21&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;Object.keys(9e19+&amp;#x27;&amp;#x27;)&lt;/code&gt; - 20&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;Object.keys(Date())&lt;/code&gt; - 19&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;Object.keys(Set+1)&lt;/code&gt; - 18 🏆&lt;/li&gt;
  &lt;/ul&gt;
  &lt;h2&gt;countOnMe2&lt;/h2&gt;
  &lt;p&gt;Рассмотрим еще один вариант этого задания:&lt;/p&gt;
  &lt;pre&gt;function countOnMe2(x) {
  if (!(x instanceof Array))
    throw &amp;#x27;x must be an array.&amp;#x27;;

  for (var i = 0; i &amp;lt; 1000; i++) {
    if (x[i] !== i) {
      throw &amp;#x27;x must contain the numbers 0-999 in order&amp;#x27;;
    }
  }

  return true;
}&lt;/pre&gt;
  &lt;p&gt;Смысл тот же, но теперь нам нужен массив не из 20 элементов, а из 1000. Плюс ко всему, здесь используется строгое сравнение &lt;code&gt;x[i] !== i&lt;/code&gt;, поэтому массив из строк нам уже не подойдет. Можем попробовать вариант с &lt;code&gt;Proxy&lt;/code&gt;: &lt;code&gt;new Proxy([],{get:(t,k)=&amp;gt;+k}). Получаем true в 29 байт ✅&lt;/code&gt;&lt;/p&gt;
  &lt;p&gt;Заметьте, что здесь мы возвращаем не просто &lt;code&gt;k&lt;/code&gt;, а &lt;code&gt;+k&lt;/code&gt;, чтобы привести строковый ключ к числу, чтобы сработало строгое сравнение. Видим, что лучшее решение состоит из 22 байт, поэтому думаем дальше.&lt;/p&gt;
  &lt;p&gt;Можем попробовать вернуться к решению с ключами массива: &lt;code&gt;[...Array(1000).keys()] // [0,1,2,3,...,998,999]&lt;/code&gt;. Это &lt;code&gt;true&lt;/code&gt; за 23 байта ✅&lt;/p&gt;
  &lt;p&gt;Нужно &amp;quot;выиграть&amp;quot; еще один байт. Идея в том, что &lt;code&gt;1000&lt;/code&gt; можно записать как &lt;code&gt;1e3&lt;/code&gt;: &lt;code&gt;1000 === 1e3 // true&lt;/code&gt;&lt;/p&gt;
  &lt;p&gt;Заменяем &lt;code&gt;1000&lt;/code&gt; на &lt;code&gt;1e3&lt;/code&gt;: &lt;code&gt;[...Array(1e3).keys()]&lt;/code&gt; и получаем &lt;code&gt;true&lt;/code&gt; за 22 байта ✅&lt;/p&gt;
  &lt;h3&gt;Решения&lt;/h3&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;code&gt;new Proxy([],{get:(i,k)=&amp;gt;+k})&lt;/code&gt; - 29&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;[...Array(1000).keys()]&lt;/code&gt; - 23&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;[...Array(1e3).keys()]&lt;/code&gt; - 22 🏆&lt;/li&gt;
  &lt;/ul&gt;
  &lt;h2&gt;countOnMe3&lt;/h2&gt;
  &lt;p&gt;И еще одна вариация этой задачи выглядит так:&lt;/p&gt;
  &lt;pre&gt;function countOnMe3(x) {
  var arrayElements = 1000;

  if (!(x instanceof Array))
    throw &amp;#x27;x must be an Array&amp;#x27;;

  for (var i = 0; i &amp;lt; arrayElements; i++)
    if (x[i] != i)
      throw &amp;#x27;x must contain the numbers 0-999 in order&amp;#x27;;

  for (element of x)
    if (element != --arrayElements)
      throw &amp;#x27;x must contain the numbers 999-0 in order&amp;#x27;;

  if (x.length !== 0)
    throw &amp;#x27;x must be empty&amp;#x27;;

  return true;
}&lt;/pre&gt;
  &lt;p&gt;Судя по коду, нам нужно передать такой массив, который &lt;strong&gt;одновременно&lt;/strong&gt; содержит числа от 0 до 999, от 999 до 0 и размер этого массива должен равняться нулю. Это три противоречащих друг-другу условия и это означает, что нам нужно придумать что-то на основе особенностей языка.&lt;/p&gt;
  &lt;p&gt;Обратим внимание на то, что второй проход по массиву происходит при помощи &lt;code&gt;for-of&lt;/code&gt;, который использует итераторы, а значит нам нужен массив, в котором будут содержаться элементы от 0 до 999, а &lt;code&gt;Symbol.iterator&lt;/code&gt; этого массива должен генерировать обратную последовательность. Таким образом мы покрываем все условия кроме последнего, а значит нужно придумать что-то еще.&lt;/p&gt;
  &lt;p&gt;Первое решение состоит в том, чтобы передать пустой массив, прототипом которого является массив с числами от 0 до 999:&lt;/p&gt;
  &lt;pre&gt;const a = [];
a.__proto__=[...Array(1e3).keys()]
a // [ length: 0, __proto__: [0,1,2,3,...,998,999] ]&lt;/pre&gt;
  &lt;p&gt;Таким образом элементы от 0 до 999 будут доступны через прототип, а вот &lt;code&gt;Symbol.iterator&lt;/code&gt; будет выполняться в контексте пустого массива, а значит ни одной итерации &lt;code&gt;for-of&lt;/code&gt; не будет выполнено. Ну и &lt;code&gt;length&lt;/code&gt; пустого массив будет равен нулю. Итого, при помощи &lt;code&gt;a=[],a.__proto__=[...Array(1e3).keys()]&lt;/code&gt; получает &lt;code&gt;true&lt;/code&gt; за 39 байт ✅&lt;/p&gt;
  &lt;p&gt;В лидерборде мы видим, что лучшее решение занимает 34 байта, а значит нам нужно придумать что-то еще.&lt;/p&gt;
  &lt;p&gt;Я предлагаю пойти по другому пути и использовать уже знакомый нам подход с &lt;code&gt;Proxy&lt;/code&gt;, но возвращать мы будем не просто переданный ключ, а &lt;strong&gt;ключ или существующее свойство&lt;/strong&gt;. Посмотрите на код:&lt;/p&gt;
  &lt;pre&gt;const x = new Proxy([], {
  get: (target, key) =&amp;gt; target[key] ?? key
});
x[0] // &amp;#x27;0&amp;#x27;
x[100] // &amp;#x27;100&amp;#x27;
x[Symbol.iterator] // function () {...}
x.length // 0&lt;/pre&gt;
  &lt;p&gt;Обратите внимание на конструкцию &lt;code&gt;target[key] ?? key&lt;/code&gt;, она использует &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator&quot; target=&quot;_blank&quot;&gt;nullish coalescing operator &lt;/a&gt;который означает, что левая часть будет использована только если она не &lt;code&gt;null&lt;/code&gt; и не &lt;code&gt;undefined&lt;/code&gt;, иначе будет использована правая часть. Посмотрите на примеры выше чтобы понять как это может нам пригодиться. Если нужного нам ключа нет в массиве, то мы возвращаем сам ключ, а если есть, то возвращаем значение по этому ключу. Таким образом мы удовлетворим все проверки в задачи:&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;code&gt;x instanceof Array&lt;/code&gt; будет &lt;code&gt;true&lt;/code&gt;, не смотря на то, что это &lt;code&gt;Proxy&lt;/code&gt;&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;x[i] != i&lt;/code&gt; внутри &lt;code&gt;for (var i = 0; i &amp;lt; arrayElements; i++)&lt;/code&gt; никогда не сработает, потому что прокси всегда будет возвращать запрошенный ключ&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;for (element of x)&lt;/code&gt; не выполнит ни одной итерации, потому что &lt;code&gt;Symbol.iterator&lt;/code&gt; выполнится в контексте пустого массива&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;x.length&lt;/code&gt; будет ноль, т.к. массив пуст&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p&gt;Итого, при помощи &lt;code&gt;new Proxy([],{get:(t,k)=&amp;gt;t[k]??k})&lt;/code&gt; получаем &lt;code&gt;true&lt;/code&gt; за 34 байта ✅&lt;/p&gt;
  &lt;h3&gt;Решения&lt;/h3&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;code&gt;a=[],a.__proto__=[...Array(1e3).keys()]&lt;/code&gt; - 39&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;new Proxy([],{get:(t,k)=&amp;gt;t[k]??k})&lt;/code&gt; - 34 🏆&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p&gt;&lt;/p&gt;
  &lt;p&gt;Вот мы и рассмотрели 3 варианта задачи &lt;code&gt;countOnMe&lt;/code&gt; c абсолютно разными подходами к решению, зачастую не самыми очевидными. Пробуйте, экспериментируйте, ищите решения, даже если кажется, что ничего нельзя придумать.&lt;/p&gt;
  &lt;tt-tags&gt;
    &lt;tt-tag name=&quot;returntrue&quot;&gt;#returntrue&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;js&quot;&gt;#js&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;javascript&quot;&gt;#javascript&lt;/tt-tag&gt;
  &lt;/tt-tags&gt;

</content></entry><entry><id>smelukov_dev:rt-length</id><link rel="alternate" type="text/html" href="https://teletype.in/@smelukov_dev/rt-length?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=smelukov_dev"></link><title>return true: length</title><published>2021-02-27T11:46:57.990Z</published><updated>2021-02-28T17:34:09.842Z</updated><category term="return-true" label="return true"></category><tt:hashtag>returntrue</tt:hashtag><tt:hashtag>javascript</tt:hashtag><tt:hashtag>js</tt:hashtag><summary type="html">Привет! Разбираем решение задачки length из второго сезона RT.</summary><content type="html">
  &lt;p&gt;Привет! Разбираем решение задачки &lt;code&gt;length&lt;/code&gt; из второго сезона &lt;a href=&quot;https://alf.nu/ReturnTrue&quot; target=&quot;_blank&quot;&gt;RT&lt;/a&gt;.&lt;/p&gt;
  &lt;blockquote&gt;⚠️ &lt;strong&gt;Статья наполнена спойлерами&lt;/strong&gt;. Если вы хотите сами решить задачу, то вернитесь к статье только после того как решите ее сами или если у вас закончится терпение &lt;/blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Задача:&lt;/strong&gt;&lt;/p&gt;
  &lt;pre&gt;function length(x) {
  return typeof x !== &amp;#x27;object&amp;#x27; &amp;amp;&amp;amp; !Array.isArray(x) &amp;amp;&amp;amp; x.length == 4
}&lt;/pre&gt;
  &lt;p&gt;Нам необходимо передать такой аргумент, который и &lt;strong&gt;не объект&lt;/strong&gt; и &lt;strong&gt;не массив&lt;/strong&gt;, но его свойство &lt;code&gt;length&lt;/code&gt; равно &lt;code&gt;4&lt;/code&gt;.&lt;/p&gt;
  &lt;p&gt;Передать &lt;code&gt;{ length: 4 }&lt;/code&gt; мы не можем, потому что это объект. &lt;code&gt;[1,2,3,4]&lt;/code&gt; тоже не сработает.&lt;/p&gt;
  &lt;p&gt;&lt;strong&gt;Что кроме массивов имеет свойство &lt;code&gt;length&lt;/code&gt; и не является при этом объектом?&lt;/strong&gt;&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;Функции&lt;/li&gt;
    &lt;li&gt;Строки&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p&gt;Свойство &lt;code&gt;length&lt;/code&gt; у функции возвращает количество параметров этой функции:&lt;/p&gt;
  &lt;pre&gt;function f(a,b,c,d) {}
console.log(f.length); // 4&lt;/pre&gt;
  &lt;p&gt;Пробуем передать &lt;code&gt;function(a,b,c,d){}&lt;/code&gt; и получаем &lt;code&gt;true&lt;/code&gt; за 19 байт ✅&lt;/p&gt;
  &lt;p&gt;Но, минимальный длина решения в лидерборде - 5 байт, а значит нам нужно придумать что-то еще. Попробуем сократить функцию до &lt;code&gt;(a,b,c,d)=&amp;gt;1&lt;/code&gt; - это 12 байт ✅&lt;/p&gt;
  &lt;p&gt;Лучше, но все равно не то.&lt;/p&gt;
  &lt;p&gt;Попробуем вариант со строками, например &lt;code&gt;&amp;#x27;1234&amp;#x27;&lt;/code&gt; - получаем &lt;code&gt;true&lt;/code&gt; за 6 байт ✅&lt;/p&gt;
  &lt;p&gt;Это еще лучше, но все еще не 5 байт.&lt;/p&gt;
  &lt;p&gt;Тут мы оказываемся в ситуации, когда ни функции, строковые литералы нам не подходят.&lt;/p&gt;
  &lt;p&gt;&lt;strong&gt;Как получиться строку длиной в 4 байта потратив при этом 5 байт?&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt;Можно воспользоваться преобразованием типов и привести что-нибудь к строке.&lt;/p&gt;
  &lt;p&gt;Подробнее &lt;a href=&quot;https://medium.com/developers-arena/type-coercion-in-javascript-c973b369b272&quot; target=&quot;_blank&quot;&gt;здесь&lt;/a&gt; (попроще) и &lt;a href=&quot;https://2ality.com/2019/10/type-coercion.html&quot; target=&quot;_blank&quot;&gt;здесь&lt;/a&gt; (посложнее).&lt;/p&gt;
  &lt;pre&gt;1 + &amp;#x27;&amp;#x27; // &amp;#x27;1&amp;#x27;
[] + &amp;#x27;&amp;#x27; // &amp;quot;&amp;quot;
NaN + &amp;#x27;&amp;#x27; // &amp;#x27;NaN&amp;#x27;
undefined + &amp;#x27;&amp;#x27; // &amp;#x27;undefined&amp;#x27;
true + &amp;#x27;&amp;#x27; // &amp;#x27;true&amp;#x27;&lt;/pre&gt;
  &lt;p&gt;Строка &lt;code&gt;&amp;#x27;true&amp;#x27;&lt;/code&gt; как раз состоит из 4 байт, это то, что нам нужно!&lt;/p&gt;
  &lt;p&gt;Но &lt;code&gt;true+&amp;#x27;&amp;#x27;&lt;/code&gt; - это 7 байт, но мы-то с вами знаем, что &lt;code&gt;true&lt;/code&gt; можно еще записать как &lt;code&gt;!0&lt;/code&gt;, поэтому попробуем сократить: &lt;code&gt;!0+&amp;#x27;&amp;#x27;&lt;/code&gt; - получаем &lt;code&gt;true&lt;/code&gt; за желанные 5 байт ✅&lt;/p&gt;
  &lt;h3&gt;&lt;strong&gt;Хронология решений&lt;/strong&gt;&lt;/h3&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;code&gt;function(a,b,c,d){}&lt;/code&gt; - 19&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;(a,b,c,d)=&amp;gt;1&lt;/code&gt; - 12&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;&amp;#x27;1234&amp;#x27;&lt;/code&gt; - 6&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;true+&amp;#x27;&amp;#x27;&lt;/code&gt; - 7&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;!0+&amp;#x27;&amp;#x27;&lt;/code&gt; - 5 🏆&lt;/li&gt;
  &lt;/ul&gt;
  &lt;tt-tags&gt;
    &lt;tt-tag name=&quot;returntrue&quot;&gt;#returntrue&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;javascript&quot;&gt;#javascript&lt;/tt-tag&gt;
    &lt;tt-tag name=&quot;js&quot;&gt;#js&lt;/tt-tag&gt;
  &lt;/tt-tags&gt;

</content></entry></feed>