<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/">
  <channel>
    <language>ru</language>
    <title>Массивы и строки</title>
    <description>Подборки задач на массивы и строки, с помощью которых вы можете закрепить свои знания по этим типам данных и подготовиться к участию в олимпиадах.</description>
    <link>https://tproger.ru/tag/arrays-and-strings</link>
    <atom:link href="https://tproger.ru/tag/arrays-and-strings/feed" rel="self" type="application/rss+xml"/>
    <lastBuildDate>Thu, 01 Oct 2026 01:35:21 GMT</lastBuildDate>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>12</sy:updateFrequency>
    <image>
      <title>Массивы и строки</title>
      <link>https://tproger.ru</link>
      <url>https://tproger.ru/apple-touch-icon.png</url>
    </image>
    <item>
      <title>Локализация через Enum, неожиданный Дзен, быстрее только телепатия</title>
      <link>https://tproger.ru/articles/lokalizaciya-cherez-enum-neozhidannyj-dzen-bystree-tolko-telepat</link>
      <comments>https://tproger.ru/articles/lokalizaciya-cherez-enum-neozhidannyj-dzen-bystree-tolko-telepat?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Самир Гёзалов]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/lokalizaciya-cherez-enum-neozhidannyj-dzen-bystree-tolko-telepat</guid>
      <description><![CDATA[<p>Надоело плодить JSON/ARB файлы при локализации Flutter-приложения? Автор делился личным опытом и показал, как элегантно настроить локализацию через Enum без внешних зависимостей, генераторов кода и боли в рантайме.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/lokalizaciya-cherez-enum-neozhidannyj-dzen-bystree-tolko-telepat">Локализация через Enum, неожиданный Дзен, быстрее только телепатия</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Алгоритмы и структуры данных]]></category>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[Массивы и строки]]></category>
      <category><![CDATA[Красивый хак]]></category>
      <category><![CDATA[Android]]></category>
      <category><![CDATA[Мобильная разработка]]></category>
      <category><![CDATA[JSON]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Flutter]]></category>
      <category><![CDATA[Dart]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 04 Jun 2026 04:45:17 GMT</pubDate>
      <content:encoded><![CDATA[<p>Решил давеча добавить локализацию в свое приложение на Flutter. Задачка-то простая: пара кнопок, пару десятков переменных. Казалось бы, делов на пять минут. Но Flutter «из коробки» сразу попытался всучить мне какую-то дичь в виде ARB и JSON файлов. Хмм, из прошлого с такими реализациями лишь печаль, так что…</p><h2>Попытка №1. Путь в лоб: Классы и интерфейсы</h2><p>Самый очевидный способ - создать родительский класс с переменными, а языки сделать его наследниками. Но это просто… фиаско. Даже если не писать from/toJson, процесс выглядит так:</p><ol><li>Объявил переменную в родителе.</li><li>Прописал её в конструкторе.</li><li>Повторил то же самое для всех дочерних классов (всех языков).</li></ol><p>Если бы я работал на аутсорсе в Индии и мне платили за количество строк кода - это был бы идеальный вариант. Но я хотел, чтобы одной строки при объявлении было достаточно.</p><h2>Попытка №2. Стандарт (ARB/JSON)</h2><p>Я поплевался, но решил попробовать - «стандарт» всё-таки. Мало ли, может чего поменялось за годы. Вроде всё завелось, но сам процесс… это боль. Бегать по разным файлам, чтобы добавить одну строчку - так себе удовольствие.</p><p>Почему я от него окончательно отказался? Когда данных становится реально много (десятки языков, тысячи строк), ты попадаешь в ловушку: тебе нужно эту махину либо целиком держать в памяти, либо постоянно подгружать и парсить. Ради смены одного слова на кнопке заставлять девайс ворочать тяжелые JSON-ы в рантайме - так себе затея для производительности.</p><h2>Попытка №3. Таблицы и костыли</h2><p>Подумал: «Окей, почему бы не подтянуть старый добрый CSV или вообще закинуть всё в табличку?». И тут официальный пакет локализации сказал: «Извини, мужик, тут наши полномочия всё».</p><p>Ну, я тоже не пальцем деланный. Решил припахать нейросеть, чтобы она написала мне собственный генератор. Флоу получился такой:</p><ol><li>Добавляю строку в таблицу.</li><li>Запускаю генератор.</li><li>Он лепит «родительский» файл.</li><li>После Freezed генерит toJson, fromJson…</li></ol><p>Короче, весело не было. Мало того, я понимал: если языков станет много, мне придется добавлять их все разом и единовременно, иначе в рантайме всё начнет плеваться ошибками. Плюс та же проблема с памятью: таблица - это структура, которую надо парсить и хранить.</p><h2>Красный флаг для программиста</h2><p>Но главная проблема даже не в этом. Необходимость запускать генератор после добавления каждой переменной - это для любого программиста красный флаг.</p><p>Что происходит на практике? Когда ты пишешь код и тебе нужно добавить одну несчастную строку, тебе лень (читать: нехочется выходить из потока творения) запускать весь этот цикл с генерацией. Ты просто её хардкодишь в надежде «потом скопом всё добавлю одним махом». А «потом» наступает тогда, когда уже весь проект завален хардкодом, и вычищать его - то еще удовольствие. Даже нейросетки с такими запросами помогают не с первого раза, и с сомнительной эффективностью.</p><p>Нутром чуял - флоу неправильный. В итоге я пришел к тому, что называю идеальной локализацией.</p><h2>Эволюция лени: почему Enum победил интерфейсы</h2><p>Я начал мучить нейросеть разными вариантами реализации. Для меня в первую очередь был важен флоу работы: мне было тупо лень писать больше одной строки кода, чтобы добавить переменную.</p><p>Моя философия проста: строку захардкодить - моментально. Добавление даже одной строки в другом файле требует доп. действий. НО, если действий минимум, то кодер поймет, что выигрыш во времени сейчас мизерный против больших потерь в будущем, и исправно добавит строку в правильное место. Этого не произойдет, если для добавления строки нужно «отчитаться» в десяти местах.</p><h2>Попытка №4. Рекорды (Records)</h2><p>Присматривался к рекордам. С ними удобно: не нужно писать конструкторы. Но есть подвох: как только ты добавил переменную в один язык, компилятор тут же сходит с ума и требует добавить её во все остальные прямо сейчас. Никакой гибкости и возможности оставить «на потом».</p><h2>Идеальный костыль: Enum</h2><p>В итоге я пришел к самому, казалось бы, «неправильному» способу, который оказался идеальным. Enum. Само название намекает на перечисления и цифры, но оказалось, что хранить в нем буквы и целые фразы - это лучший путь для локализации.</p><p>Знаете, мне моё решение так понравилось, что я пошел к нейросетям и проверил его со всех сторон. Все модели  остались в полном восторге. Под это дело я даже подготовил монументальную «нейро-статью» на полтора часа внимательного чтения, со всеми графиками, бенчмарками и анализом производительности.</p><p>Но потом я заглянул в правила Хабра, прислушался к голосу разума и понял: никто не хочет читать полтора часа сухой статистики. Лучше я просто расскажу вам свою историю «от первого лица», как я докатился до такой жизни. Ну, а если вы совсем уж фанаты цифр - просто скормите этот текст любой нейронке, она вам перескажет всё в лучших академических тонах с графиками на любой вкус.</p><p>А здесь мы будем говорить по делу.</p><p>Ниже я выкатываю сам код. Код тут не для зубрежки, а лишь чтобы указать направление / идею. Самая большая прелесть этой системы в том, что она оставляет гигантское пространство для любого типа реализации. Это архитектурный каркас, который чертовски сложно сломать. Главное — уловить принцип.</p><h2>Реализация</h2><p>Принцип разделения:</p><ul><li>enum Strings → типизированный контракт (что существует).</li><li>translator → источник данных (откуда берётся текст).</li></ul><p>Структура файлов - минимальная. Никаких внешних зависимостей:</p><h2>Ядро - strings.dart</h2><p>Весь контракт локализации в одном enum. Два режима - хардкод switch и серверный кеш - за одним и тем же</p><p>. Даже сообщения об ошибках локализации — сами локализованы:</p><h2>Список языков - languages_enum.dart</h2><p>Каждый язык - самодостаточная единица: знает свой код, название, направление текста и как себя загрузить:</p><p>Хотите грузить с сервера? Одна строка + loader. И</p><p>- тоже одна строка, потому что</p><p>уже является registry:</p><h2>Переводчик - i18n/russian.dart</h2><p>Как это выглядит в жизни (и почему я перестал хардкодить) Я намеренно не привожу здесь код оберток виджетов или конкретных стейт-менеджеров. Всё это - чистая «вкусовщина». Для работы системы нужен лишь элементарный вещатель событий (Notifier), повешенный на метод смены языка.</p><p>Но главное - это мой ежедневный флоу. Сейчас, чтобы добавить строку в UI, я просто вызываю нужный мне ключ: Strings.someKey(). Без контекста, везде.</p><p>А если ключа еще нет? Я тупо иду в Strings и добавляю одну строчку в Enum. Всё.</p><p>Благодаря дефолтному конструктору, приложению абсолютно плевать, что у меня там еще 100 языков не переведены. Оно компилируется и работает здесь и сейчас. А дальше в дело вступают гит-хуки: при комите нейросетка сама подхватывает изменения и заполняет недостающие поля в переводчиках.</p><p>Знаете, какое самое странное чувство? Мне сейчас реально проще и быстрее завести переменную в локализации, чем хардкодить строку в коде. Кажется, это и есть признак здоровой архитектуры - когда делать «правильно» становится физически удобнее, чем делать «быстро» и криво.</p><p>Собственно если в кратце это все о чем я хотел рассказать. Если тема зайдет или кто-то сам не сможет допереть, как прикрутить это к своей архитектуре - пишите в комментариях, разберемся.</p><p>Надеюсь, мой опыт сэкономит вам пару литров нервных клеток. Всех благ и чистого кода без «магических строк»!</p>]]></content:encoded>
    </item>
    <item>
      <title>Массивы в PHP: типы и операции</title>
      <link>https://tproger.ru/articles/massivy-v-php</link>
      <comments>https://tproger.ru/articles/massivy-v-php?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Рафаил Агазода]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/massivy-v-php</guid>
      <description><![CDATA[<p>Составили шпаргалку по массивам в PHP для начинающих. Рассказали о типах массивов в PHP и об операциях, которые можно совершить над ними.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/massivy-v-php">Массивы в PHP: типы и операции</a>»</p>]]></description>
      <category><![CDATA[Массивы и строки]]></category>
      <category><![CDATA[Для начинающих]]></category>
      <category><![CDATA[Шпаргалки]]></category>
      <category><![CDATA[PHP]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 10 Oct 2023 11:39:44 GMT</pubDate>
      <content:encoded><![CDATA[<p>В PHP массивы представляют собой мощный инструмент для хранения, обработки и управления данными. Они позволяют программистам организовывать информацию в упорядоченные коллекции и обращаться к ней по ключу или индексу.</p><p>В PHP есть несколько типов массивов, включая индексированные и ассоциативные массивы, а также многомерные и вложенные массивы, которые обеспечивают гибкость при работе с данными различной структуры.</p><p>В этой статье мы рассказываем о типах массивов в PHP и об операциях, которые можно совершить над ними.</p><ol><li><a href="https://tproger.ru/#one">Типы массивов в PHP</a></li><li><a href="https://tproger.ru/#two">Как создавать массивы в PHP</a></li><li><a href="https://tproger.ru/#three">Как получить элемент массива в PHP по индексу</a></li><li><a href="https://tproger.ru/#four">Как добавить элемент в конец массива PHP</a></li><li><a href="https://tproger.ru/#five">Как удалить последний элемент массива PHP</a></li><li><a href="https://tproger.ru/#six">Получение длины массива в PHP</a></li><li><a href="https://tproger.ru/#seven">Как проверить наличие элемента массива в PHP</a></li><li><a href="https://tproger.ru/#eight">Как выполнить обход массива в PHP и вывести его элементы</a></li><li><a href="https://tproger.ru/#nine">Как выполнить слияние массивов в PHP</a></li><li><a href="https://tproger.ru/#ten">Как сортировать массив в PHP</a></li></ol><h2>Типы массивов в PHP</h2><h3>1. Индексированные массивы</h3><p>Это самый обычный тип массива в PHP, где элементы нумеруются целыми числами, начиная с 0, и последовательно увеличиваются.</p><h3>2. Ассоциативные массивы</h3><p>В данном типе массивов элементы хранятся в парах ключ-значение, где ключи могут быть строками или целыми числами.</p><h3>3. Многомерные массивы</h3><p>Это тип массива, в котором элементы сами могут быть другими массивами. Такие массивы позволяют хранить иерархически связанные данные.</p><h3>4. Вложенные массивы</h3><p>Это тип массива, в котором элементы могут содержать другие массивы, создавая более сложную структуру данных.</p><h2>Как создавать массивы в PHP</h2><h3>1. Создание пустого массива</h3><p>Создание пустого массива в PHP может быть полезным для программистов, когда они хотят создать массив, к которому будут добавлять элементы в ходе выполнения программы.</p><p>Пустой массив предоставляет исходную точку, с которой можно начать добавлять элементы и формировать коллекцию данных.</p><p>или</p><h3>2. Создание индексированного массива</h3><p>Индексированные массивы в PHP полезны, когда нужно хранить упорядоченную коллекцию значений и обращаться к ним по числовым индексам. Можно использовать индексированный массив, например, для хранения списка элементов, результатов операций или последовательности данных.</p><p>Использование числовых индексов позволяет эффективно обращаться к элементам массива по их позиции.</p><p>или</p><h3>3. Создание ассоциативного массива</h3><p>Ассоциативные массивы в PHP полезны, когда нужно хранить данные в виде пар “ключ” =&gt; “значение”.</p><p>Ассоциативные массивы позволяют, например, хранить информацию о пользователях, настройках приложения, пунктах меню или любых других связанных данных.</p><p>Использование ключей позволяет быстро извлекать и обновлять значения в массиве по имени.</p><p>или</p><h3>4. Создание многомерного массива</h3><p>Многомерные массивы в PHP позволяют хранить данные в виде таблицы с несколькими рядами и столбцами, где каждая ячейка может содержать значение.</p><p>Также многомерные массивы представляют собой массивы, в которых элементами являются другие массивы.</p><p>Это особенно полезно при работе с матрицами, реляционными базами данных или любыми случаями, когда данные нужно организовать в иерархическую структуру.</p><p>или</p><h2>Как получить элемент массива в PHP по индексу</h2><h3>1. Оператор квадратных скобок []</h3><p>Этот способ наиболее распространен и прост в использовании. Можно использовать оператор квадратных скобок [] и указать индекс элемента внутри них.</p><h3>2. Функция array_values()</h3><p>Данная функция возвращает все значения массива в виде нового массива, с индексами, начиная с 0. Затем можно получить элемент массива по новому индексу.</p><h3>3. Функции current() и next()</h3><p>Эти функции позволяют перемещаться по массиву и получать текущий элемент. Функция current() возвращает текущий элемент массива, а функция next() сдвигает указатель на следующий элемент.</p><h2>Как добавить элемент в конец массива PHP</h2><h3>1. Использование оператора []</h3><p>Самым простым способом является использование оператора квадратных скобок [] с пустым индексом, чтобы добавить элемент в конец массива.</p><h3>2. Использование функции array_push()</h3><p>Функция array_push() позволяет добавить один или более элементов в конец массива. Синтаксис функции следующий: array_push($array, $element1, $element2, ...).</p><h3>3. Использование оператора +=</h3><p>Еще одним способом является использование оператора +=, который объединяет два массива. Если левым операндом является пустой массив, то элементы будут добавлены в конец массива</p><h2>Как удалить последний элемент массива PHP</h2><h3>1. Функция array_pop()</h3><p>В результате выполнения этого кода последний элемент (“5”) будет удален из массива, а значение этого элемента будет сохранено в переменной `$lastElement`</p><h3>2. Функция unset()</h3><p>При использовании функции unset() вы указываете индекс последнего элемента массива, который нужно удалить, используя count($myArray) - 1. Это вычисляет индекс последнего элемента массива.</p><h3>3. Оператор array_slice()</h3><p>Оператор array_slice() возвращает часть массива, начиная с индекса 0 и заканчивая индексом -1 (или индексом последнего элемента минус единица). В результате получается массив без последнего элемента.</p><h3>4. Функция array_splice()</h3><p>Функция array_splice() изменяет исходный массив, удаляя элементы, начиная с указанного индекса. В данном случае мы указываем индекс -1, чтобы удалить последний элемент массива.</p><h2>Получение длины массива в PHP</h2><h3>1. Функция count()</h3><p>Функция count() возвращает количество элементов в массиве. В результате выполнения этого кода переменная $length будет содержать длину массива, то есть значение “5”.</p><h3>2. Оператор sizeof()</h3><p>Оператор sizeof() работает аналогично функции count() и также возвращает количество элементов в массиве.</p><h3>3. Функция arraycountvalues()</h3><p>Функция array_count_values() возвращает ассоциативный массив, где ключами являются уникальные значения из исходного массива, а значениями – количество вхождений каждого значения.</p><p>В данном случае мы используем count() для получения длины ассоциативного массива, чтобы узнать количество уникальных значений в исходном массиве.</p><h3>4. Цикл foreach</h3><p>Мы итерируемся по каждому элементу массива с помощью цикла foreach и увеличиваем переменную $length на 1 для каждого элемента. В результате выполнения этого кода длина массива будет сохранена в переменной $length.</p><h2>Как проверить наличие элемента массива в PHP</h2><h3>1. Оператор in_array()</h3><p>Оператор in_array() проверяет, содержится ли указанный элемент в массиве. В этом примере переменная $exists будет содержать значение true, так как элемент `3` содержится в массиве $myArray.</p><h3>2. Функция array_search()</h3><p>Функция array_search() возвращает индекс элемента в массиве, если он найден. Если элемент не найден, функция возвращает false.</p><p>В данном случае мы проверяем, не равен ли индекс false, чтобы определить, содержится ли элемент в массиве.</p><h3>3. Функция array_key_exists()</h3><p>Функция array_key_exists() проверяет, содержится ли указанный ключ в массиве. В этом примере переменная $exists будет содержать значение true, так как ключ 'key2' существует в массиве $myArray.</p><h3>4. Оператор isset()</h3><p>Оператор isset() проверяет, определен ли указанный элемент или ключ в массиве. В данном случае переменная $exists будет содержать значение true, так как элемент с ключом 'key2' определен в массиве $myArray.</p><h2>Как выполнить обход массива в PHP и вывести его элементы</h2><h3>1. Цикл for</h3><p>В этом примере мы используем цикл for, чтобы пройти через каждый индекс массива и вывести его элементы. Код echo $myArray[$i] . ", "; выводит каждый элемент массива, за исключением последнего, и добавляет запятую после каждого элемента.</p><h3>2. Цикл foreach</h3><p>Цикл foreach автоматически итерирует по каждому элементу массива и выполняет указанные действия для каждого элемента. В этом примере мы выводим каждый элемент массива, добавляя запятую после каждого элемента.</p><h3>3. Цикл while с использованием функций current() и next()</h3><p>С помощью функции reset() мы устанавливаем указатель текущего элемента массива в начало. Затем, с помощью цикла while, мы получаем текущий элемент с помощью функции current(), выводим его и перемещаем указатель на следующий элемент с помощью функции next(). Цикл продолжается до тех пор, пока есть элементы в массиве.</p><h2>Как выполнить слияние массивов в PHP</h2><h3>1. Оператор "+"</h3><p>Оператор + объединяет элементы обоих массивов, и дубликаты удаляются, чтобы сохранить только уникальные значения.</p><p>Вывод:</p><h3>2. Функция arraymerge()</h3><p>Функция arraymerge() объединяет элементы обоих массивов в новый массив, сохраняя исходные ключи. Если есть одинаковые ключи, то значение из второго массива заменит значение из первого массива.</p><p>Вывод:</p><h3>3. Оператор "…" в PHP 7.4 и более поздних версиях</h3><p>С помощью оператора ... (spread operator) мы можем распаковать элементы массивов и объединить их в новый массив.</p><p>Вывод:</p><h3>4. Функция arraymergerecursive()</h3><p>Функция arraymergerecursive() объединяет элементы обоих массивов в новый массив, сохраняя все значения в виде массивов, если ключи совпадают.</p><p>Вывод:</p><h2>Как сортировать массив в PHP</h2><h3>1. Функция sort()</h3><p>Функция sort() сортирует массив в порядке возрастания, переиндексируя элементы массива.</p><p>Вывод:</p><h3>2. Функция rsort()</h3><p>Функция rsort() сортирует массив в порядке убывания, переиндексируя элементы массива.</p><p>Вывод:</p><h3>3. Функция asort()</h3><p>Функция asort() сортирует массив в порядке возрастания, сохраняя связь ключей и значений.</p><p>Вывод:</p><h3>4. Функция arsort()</h3><p>Функция arsort() сортирует массив в порядке убывания, сохраняя связь ключей и значений.</p><p>Вывод:</p><h3>5. Функция ksort()</h3><p>Функция ksort() сортирует массив по ключам в порядке возрастания, сохраняя связь ключей и значений.</p><p>Вывод:</p><h3>6. Функция krsort()</h3><p>Функция krsort() сортирует массив по ключам в порядке убывания, сохраняя связь ключей и значений.</p><p>Вывод:</p><h2>Заключение</h2><p>Массивы в PHP играют ключевую роль в хранении и управлении данными.</p><p>Благодаря разнообразию типов массивов разработчики могут эффективно структурировать данные. Операции над массивами позволяют динамически работать с данными и преобразовывать их согласно требованиям проекта.</p><p>Надеемся, шпаргалка оказалась полезной вам, и вы узнали много нового.</p><p>Напишите в комментариях, если эта статья помогла вам. Также укажите, чего в ней может не хватать, чем можно дополнить материал или какие новые статьи по PHP нам стоит опубликовать. Мы будем рады обратной связи. 🙂</p>]]></content:encoded>
    </item>
    <item>
      <title>Что было добавлено в ECMAScript в 2023 году</title>
      <link>https://tproger.ru/articles/chto-bylo-dobavleno-v-ecmascript-v-2023-godu</link>
      <comments>https://tproger.ru/articles/chto-bylo-dobavleno-v-ecmascript-v-2023-godu?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Рафаил Агазода]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/chto-bylo-dobavleno-v-ecmascript-v-2023-godu</guid>
      <description><![CDATA[<p>Рассказываем, что было добавлено в ECMAScript в 2023 году. Это стандарт JavaScript, который устанавливает правила и синтаксис JS-кода.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/chto-bylo-dobavleno-v-ecmascript-v-2023-godu">Что было добавлено в ECMAScript в 2023 году</a>»</p>]]></description>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[Массивы и строки]]></category>
      <category><![CDATA[Языки программирования]]></category>
      <category><![CDATA[TypeScript]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 29 May 2023 09:25:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>ECMAScript – это стандарт языка программирования JavaScript, который устанавливает правила, синтаксис и другие критерии создания JavaScript-кода.</p><p>ECMAScript ежегодно дополняется сообществом разработчиков JavaScript и соответствует стандартам ECMA International. Самые последние обновления ECMAScript включают в себя новые функции и методы, которые помогают разработчикам писать более гибкий и мощный код.</p><p>Эти обновления позволяют создавать более качественные и быстрые веб-приложения, а также обеспечивают возможность масштабирования и поддержки кода в будущем.</p><p>Обновления помогают большинству веб-приложений стать более мощными и производительными, что расширяет возможности для создания инновационных и уникальных приложений на основе JavaScript.</p><p>Вот, какие функции были добавлены в ECMAScript в 2023 году.</p><p>UPD: Рассказали, что <a href="https://tproger.ru/articles/ecmascript-2024">планируется внедрить в ECMAScript в 2024 году</a>.</p><h2>1. Поиск элемента в массиве</h2><p>Эта функция позволяет найти последний элемент массива, соответствующий заданному условию.</p><h2>2. Грамматика Hashbang</h2><p>Эта функция позволит нам использовать Hashbang/Shebang в некоторых CLI.</p><p>Shebang представлен #! и представляет собой специальную строку в начале скрипта, которая сообщает операционной системе, какой интерпретатор использовать при выполнении скрипта.</p><p>Строка #!/usr/bin/env node вызывает исходный файл Node.js напрямую как исполняемый файл.</p><p>Нам не понадобится строка #!/usr/bin/env node для явного вызова файла через интерпретатор узла, например, node ./file.</p><h2>3. Символы-ключи в WeakMap</h2><p>Теперь можно использовать уникальные символы в качестве ключей.</p><p>До этого обновления WeakMaps можно было использовать в качестве ключей только объекты. Объекты используются в качестве ключей для WeakMaps, потому что они имеют один и тот же аспект идентичности.</p><p>Symbol — это единственный примитивный тип в ECMAScript, который позволяет использовать для него уникальные значения. Использовать Symbol теперь можно и в качестве ключа вместо создания нового объекта с помощью WeakMap.</p><p>Здесь указаны другие варианты использования, связанные с <a href="https://github.com/tc39/proposal-symbols-as-weakmap-keys#shadowrealms-membranes-and-virtualization">ShadowRealms</a> и <a href="https://github.com/tc39/proposal-symbols-as-weakmap-keys#record-and-tuples">Record &amp; Tuples</a> и с использованием символов в качестве WeakMaps.</p><h2>4. Изменить массив через копирование</h2><p>Обновление предоставляет дополнительные методы в Array.prototype для внесения изменений в массив, возвращая его новую копию с изменением вместо обновления исходного массива.</p><p>Новые введенные функции Array.prototype:</p><ol><li>Array.prototype.toReversed()</li><li>Array.prototype.toSorted(compareFn)</li><li>Array.prototype.toSpliced (start, deleteCount, … items)</li><li>Array.prototype.with(index, value)</li></ol><p>Обновления ECMAScrpit принесли потрясающий набор новых функций, которые серьёзно облегчают кодинг. Если вы уже успели опробовать новые функции, напишите в комментариях, удобнее ли вам стало работать.</p><p>Удачного кодинга!</p>]]></content:encoded>
    </item>
    <item>
      <title>Unicode: визуализация занятого пространства и объяснение тех аспектов, которые должен знать каждый программист</title>
      <link>https://tproger.ru/translations/unicode-intro</link>
      <comments>https://tproger.ru/translations/unicode-intro?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Тарас Сереванн]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/translations/unicode-intro</guid>
      <description><![CDATA[<p>Unicode — сложный стандарт на тысячу страниц с внутренней структурой, кодовыми точками и поддержкой более чем 1100 языков.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/translations/unicode-intro">Unicode: визуализация занятого пространства и объяснение тех аспектов, которые должен знать каждый программист</a>»</p>]]></description>
      <category><![CDATA[Массивы и строки]]></category>
      <category><![CDATA[Работа с кодировками]]></category>
      <category><![CDATA[Unicode]]></category>
      <category><![CDATA[Переводы]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 12 Mar 2017 18:43:47 GMT</pubDate>
      <content:encoded><![CDATA[<p>Unicode — это слово вызывает страх и трепет в сердцах миллионов программистов по всему миру. Несмотря на то, что все мы пытаемся «поддерживать Unicode» в нашем софте, Unicode — это не просто использование wchar_t для строк, это стандарт из тысячи страниц и десятки дополнений к нему. Поэтому спустя 30 лет после появления Unicode многие программисты всё ещё понятия не имеют, что же это на самом деле такое.</p><h3>Разнообразие и сложность</h3><p>Как только вы начинаете изучать Unicode, сразу же становится понятно, что это “явление” намного сложнее, чем та же таблица ASCII, с которой вы уже можете быть знакомы. Дело не только в том, что Unicode содержит намного больше символов. Unicode имеет сложную внутреннюю структуру, фичи и набор разноцветных костылей, и это явно не те вещи, которые вы ожидаете от простой таблицы символов.</p><p>Но во многом именно благодаря этому Unicode поддерживает все или почти все системы письменности, которые существуют в мире: на сегодня этот стандарт поддерживает более чем 1100 языков. Но его задача не только в том, чтобы вместить все возможные языки, но и в том, чтобы позволить им сосуществовать в одном тексте — это делает задачу ещё сложнее.</p><p>Тем не менее, разбираться в особенностях Unicode всё-таки следует любому программисту: подумайте о миллионах людей, которые смогут использовать ваше ПО на своем родном языке.</p><h3>Кодовое пространство</h3><p>Начнем с основ. Базовые элементы — это символы, хотя правильнее будет всё же использовать термин «кодовые точки». Кодовые точки определяются по шестнадцатеричному номеру и префиксу «U+». Например, U+0041 это латинская буква «A», а U+03B8 — греческая «θ». Каждая кодовая точка также имеет собственное название и ещё несколько характеристик, указанных в <a href="http://www.unicode.org/reports/tr44/">базе данных символов</a> Unicode.</p><p>Множество всех возможных кодовых точек называется кодовым пространством. Кодовое пространство Unicode состоит из 1 114 112 кодовых точек. Но лишь 128 237 (12%) из них на самом деле являются занятыми: более чем достаточно места для роста. Юникод также резервирует 138 468 кодовых точек для «приватного использования», то есть для внутренних нужд различных приложений.</p><h3>Распределение кодового пространства</h3><p>Лучший способ что-то понять — использовать визуализацию. (Кстати, если вы хотите понять суть каких-нибудь алгоритмов, у нас есть для вас <a href="https://tproger.ru/digest/8-algorithm-visualizers/">подборка сервисов</a> с визуализацией алгоритмов.) Ниже представлена карта всего кодового пространства, каждый пиксель соответствует одной кодовой точке. Для удобства карта поделена на поля (маленькие квадраты) размером 16×16 = 256 кодовых точек. Каждое большое поле содержит 65 536 кодовых точек. Всего существует 17 больших полей.</p><figure><img src="https://media.tproger.ru/uploads/2017/03/codespace-map.png" alt="" /></figure><p>Белым цветом помечено незанятое пространство, синим — уже определенные символы, а зеленым — приватные кодовые точки. Красным цветом обозначены суррогатные точки, которые являются результатом особенностей кодирования в UTF-16, о них мы поговорим позже.</p><p>Первое большое поле называется «Базовое мультиязычное поле». Оно содержит почти все символы, которые используются в современных текстах, включая латинские буквы, кириллицу, греческий, китайский, японский, корейский и так далее. В своей первой версии Unicode состоял только из этого поля и был расширен лишь в 1996 году.</p><p>Второе поле содержит исторические и специальные символы, например, сумерийскую клинопись, египетские иероглифы и эмодзи. Третье поле содержит небольшое количество менее известных китайских символов. Остальные поля остаются пустыми, не считая небольшого количества редко используемых символов форматирования в 15 поле. Поля 16-17 целиком в приватном использовании.</p><h3>Языки, поддерживаемые Unicode</h3><p>Давайте сосредоточимся на первых трех полях, именно там происходит всё самое интересное:</p><figure><img src="https://media.tproger.ru/uploads/2017/03/script-map.png" alt="" /></figure><p>Эта цветная карта обозначает 135 различных языков юникода. Китайский (бирюзовый) и корейский (коричневый) занимают основную часть базового поля (левый большой квадрат). Для сравнения, все европейские, средневосточные и южноазиатские языки вместились в первую строку базового поля.</p><p>По частоте использования в реальном мире лидирует первое поле, исключением являются эмодзи — они завоевали наши сердца, находясь во втором поле.</p><h3>Кодировки</h3><p>Как вы узнали раньше, кодовые точки задаются номерами с U+0000 по U+10FFFF. Но как эти номера хранятся в реальной памяти компьютера? Использование первого, что приходит в голову — обычного 32-битного целочисленного типа — было бы очень ресурсоемким и не оправданным. Нам понадобилось бы по 4 байта на каждую кодовую точку. Поэтому тут на помощь нам приходят стандарты кодирования UTF — Unicode Transformation Format.</p><p>Некоторые программисты считают, что Unicode и UTF — это разные вещи, но на самом деле UTF-8, UTF-16 и UTF-32 являются лишь стандартами преобразования UTF, которые позволяют значительно сэкономить память и повысить скорость обработки.</p><p>Например, в UTF-8 символы с кодами меньше 128 представляются всего одним байтом, а так как в Юникоде они повторяют ASCII, то текст, написанный только этими символами, будет являться текстом в ASCII — это позволяет избежать лишних конвертаций. Символы же с кодами от 128 до 65536 кодируются 2-мя байтами, аналогично существуют 3-байтные и 4-байтные коды.</p><p>Смысл UTF-16 и UTF-32 в том, чтобы представить ещё большую часть Unicode как обычную таблицу, подобную ASCII. Например, UTF-32 — это и есть большая таблица ASCII для всего юникода, но в 99% случаев хватает и UTF-8.</p><h3>Комбинации знаков</h3><p>До этого мы обсуждали только кодовые точки, но в юникоде символ может быть больше, чем одной кодовой точкой. Комбинации созданы для экономии памяти: именно с их помощью ставятся ударения и другие крючочки под и над буквами.</p><p>Например, букву под ударением (Á) можно описать таким образом: U+0041 (A) + U+0301 (`).</p><p>Видели в интернете м̵͉̪̫̳̖͌͋͗͌̑̎а̬̜ͣͤг̘͎̹̜͕̤͊̊̽и͕̽͌ͮͬ͡ю͉͑̏ ̛̹̬̜̪̳̹̙̿̄͋̏т̹̫͚̱̩ͅи̼̬̤̓͒ͨ̅́́̚̚п̗̔̒ͧ̇ͩ̐̔а̺̄͆ͭ ̢̜͉̮̭͚ͬ͒͐̈̚т̛̦̖͎̪̭͇̓а̛͙̳̼̺̲̜̂ͮͦ̈́̃̈́ͣк̳̘̝̔́о͉̜̆̈́й͉͍̜͛͆́̀? Она создается именно с помощью комбинации знаков.</p><h3>И это только начало</h3><p>Эта статья содержит более 5 000 символов, но на самом деле является лишь верхушкой айсберга. Юникод полон других сложных вещей: чего стоят одни только применения (mapping), сопоставления (collation) и двунаправленный текст. Но и это далеко не всё.</p><p>Юникод — очень сложная система. И хотя для работы программистом вам не обязательно понимать её полностью, некоторые знаний всё-таки станут полезными на практике.</p><p>Если хотите узнать больше, то можете прочитать следующие материалы:</p><ul><li><a href="http://www.unicode.org/versions/latest/">Стандарт</a>;</li><li><a href="http://utf8everywhere.org/">Манифест «UTF-8 везде»</a>;</li><li><a href="https://eev.ee/blog/2015/09/12/dark-corners-of-unicode/">Темная сторона юникода</a>;</li><li><a href="https://www.google.com/get/noto/">Google Noto Fonts</a> — шрифты, покрывающие весь спектр Unicode.</li></ul><p>Но что вы точно обязаны сделать, так это поблагодарить юникод за то, что мы больше никогда не вернемся в старые времена несовместимых кодировок.</p><p>Спасибо, юникод.</p>]]></content:encoded>
    </item>
    <item>
      <title>Задача на поиск «волшебного» индекса в массиве</title>
      <link>https://tproger.ru/problems/magic-index-search</link>
      <comments>https://tproger.ru/problems/magic-index-search?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Лапа]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/problems/magic-index-search</guid>
      <description><![CDATA[<p>Метод находит индекс i, для которого A[i] равно i, в массиве без повторов: решение перебором и вариант, когда таких индексов несколько.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/problems/magic-index-search">Задача на поиск «волшебного» индекса в массиве</a>»</p>]]></description>
      <category><![CDATA[Массивы и строки]]></category>
      <category><![CDATA[Задачи умеренной сложности]]></category>
      <category><![CDATA[Задачки]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 03 Oct 2016 19:26:34 GMT</pubDate>
      <content:encoded><![CDATA[<p>В массиве случайных чисел A[0…n-1] задан один «волшебный» индекс: такой, что A[i] = i. Значения элементов в массиве повторяться не могут. Учитывая, что массив отсортирован по значениям в порядке возрастания, напишите метод, который определит этот «волшебный» индекс, если он существует в массиве A. Если элемента в массиве нет, верните любое отрицательное число.</p><p>Дополнительно:<br />Как изменится решение, если известно, что таких индексов в массиве несколько?</p><h3>Решение</h3><p>Можно решать такую задачу «в лоб», и в таком подходе нет ничего зазорного. Мы просто пройдемся по массиву и отыщем элемент, соответствующий условию.</p><p>Но этому решению требуется обойти весь массив от начала до искомого элемента. Массив отсортирован, и, вероятно, мы должны этим воспользоваться.</p><p>Так задача становится похожа на классическую задачу <a href="https://tproger.ru/translations/binary-search-tree-for-beginners/">бинарного поиска</a>. Для алгоритма больше всего подходит способ «сопоставления с образцом».</p><p>При бинарном поиске мы берем элемент k и сравниваем его с элементом из середины массива, x, чтобы определить, по какую сторону от x находится искомого k — слева или справа. Давайте попробуем определить, где может находиться «волшебный» элемент на примере. Взгляните на массив (нижняя строка — индексы элементов):</p><figure><img src="https://media.tproger.ru/user-uploads/46677/2023-12-27/4e9644ac-2468-4d36-a168-3c8d7cdc2d67.png" alt="" /></figure><p>Если взять элемент из середины массива, A[5] = 3, то становится ясно, что «волшебный» элемент должен находиться правее, так как A[mid] &lt; mid. Почему в этой ситуации элемент не может быть слева? Индекс элемента в данном случае уже больше значения (5 &gt; 3). Значит, все значения элементов с индексами 0-4 будут меньше самих индексов.</p><p>При движении в направлении от i к i-1 значение элемента будет уменьшаться не менее чем на 1 (так как массив отсортирован и не содержит одинаковых элементов). Если средний элемент меньше искомого, то при движении влево, смещаясь на k индексов и (как минимум) на k значений, мы будем попадать на еще более маленькие значения.</p><p>Наш алгоритм будет по такому принципу выяснять, где должен находиться искомый элемент — справа или слева, и проверять только одну половину массива. Этим мы сокращаем число итераций, необходимых для того, чтобы наткнуться на нужный элемент.</p><p>При использовании рекурсивного решения алгоритм похож на бинарный поиск.</p><p>Дополнительно: как изменится решение, если таких индексов окажется несколько?</p><p>Если элементы массива повторяются, то наш алгоритм не будет работать. Давайте рассмотрим следующий массив:</p><p>Если A[mid] &lt; mid, сказать заранее, где будут находиться «волшебные» элементы, становится сложнее.</p><figure><img src="https://media.tproger.ru/user-uploads/46677/2023-12-27/008a7bd6-1892-4614-a48d-1a8981da44d5.png" alt="" /></figure><p>Могут ли в этом массиве они находиться слева? Нет. Так как A[5] = 3, мы знаем, что A[4] никак не может быть «волшебным» элементом. A[4] должен быть равен 4, но в то же время мы знаем, что A[4] не может быть больше, чем A[5], из-за условия отсортированности.</p><p>Фактически, если мы видим, что A[5] = 3, нам достаточно проанализировать только правую сторону, как это и делалось раньше. Но чтобы найти элемент в левой части, можно пропустить группу элементов и произвести поиск только среди A[0] ‒ A[3], где A[3] — это первый элемент, который может быть «волшебным».</p><p>В общем, нам нужно взять элемент из середины массива и сравнить его индекс с его же значением — midIndex с midValue. Если они совпадают, то возвращаем значение сразу. Иначе выясняем, больше или меньше значение элемента из середины его индекса. В зависимости от полученного результата начинаем искать либо слева, либо справа.</p><ul><li>Левая сторона: поиск среди элементов от start до Math.min(midIndex - 1, midValue).</li><li>Правая сторона: поиск среди элементов от Math.Max(midIndex + 1, midValue) до end.</li></ul><p>Если же переданы ошибочные параметры, пусть код возвращает -1.</p><p>Представленный ниже код реализует данный алгоритм:</p><p>Этот код работает в том числе и для случая без дополнительного условия.</p>]]></content:encoded>
    </item>
    <item>
      <title>Как быстро конкатенировать строки в Python</title>
      <link>https://tproger.ru/translations/speedy-string-concatenation-python</link>
      <comments>https://tproger.ru/translations/speedy-string-concatenation-python?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Пётр Соковых]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/translations/speedy-string-concatenation-python</guid>
      <description><![CDATA[<p>Преподаватель Рювен Лэрнер сравнил способы объединения строк в Python и выяснил, какой из них оказывается самым эффективным на практике.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/translations/speedy-string-concatenation-python">Как быстро конкатенировать строки в Python</a>»</p>]]></description>
      <category><![CDATA[Массивы и строки]]></category>
      <category><![CDATA[Оптимизация]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Переводы]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 19 Sep 2016 17:31:41 GMT</pubDate>
      <content:encoded><![CDATA[<p>Рассказывает Рювен Лэрнер, преподаватель</p><p>Как вы, наверное, знаете один из принципов в Python: “Должен быть один и только один способ сделать что-либо”. Можете убедиться в этом, выполнив в в интерпретаторе import this (вы увидите <a href="https://www.python.org/dev/peps/pep-0020/">Дзен Python</a>). Несмотря на это, иногда вам всё равно приходится выбирать между несколькими способами сделать что-то, и не всегда очевидно, какой способ лучше. Недавно один студент спросил меня, какой способ конкатенации строк в Python самый эффективный. Я решил поделиться результатом своего маленького исследования и с вами.</p><p>Для начала вспомним, какие способы объединения строк предоставляет нам Python. Во-первых, это оператор +:</p><p>Также мы можем использовать оператор %, который, конечно, может использоваться не только для соединения строк, но и для этого тоже:</p><p>Есть и ещё более современная замена % — это str.format:</p><p>Так же, как и %, этот метод гораздо мощнее, чем обычный +, но тем не менее строки соединяют и с его помощью.</p><p>Как же мы будем замерять время? В <a href="https://ru.wikipedia.org/wiki/IPython">Jupyter</a> (так же известном, как IPython) мы можем использовать магическую команду timeit для запуска кода. Для запуска я подготовил четыре функции, каждая из которых складывает строки разным образом. Исходные строки хранятся в глобальных переменных (x и y), а локальная (для каждой функции) переменная z содержит результат сложения. Затем функция возвращает результат.</p><p>Конечно concat3() и concat4() фактически одинаковы, но я решил проверить и то, влияет указание порядка строк на скорость или нет. Затем я определил наши глобальные переменные:</p><p>И запустил наши функции:</p><p>Результат оказался следующим:</p><ul><li>concat1: 153 наносекунды;</li><li>concat2: 275 наносекунд;</li><li>concat3: 398 наносекунд;</li><li>concat4: 393 наносекунды.</li></ul><p>Здесь мы можем видеть, что concat1(), который использует оператор +, выполняется гораздо быстрее остальных. Это немного расстроило меня, потому что мне очень нравится str.format, однако теперь в задачах, которые требуют огромного количества обработки строк, от него придётся отказаться.</p><p>Возможно, такие результаты могут быть связаны с тем, что короткие строки не создаются в Python каждый раз снова, а хранятся в специальной таблице? Давайте попробуем изменить наши глобальные переменные следующим образом:</p><p>Теперь мы получим следующие результаты:</p><ul><li>concat1: 2.64 микросекунды;</li><li>concat2: 3.09 микросекунды;</li><li>concat3: 3.33 микросекунды;</li><li>concat4: 3.48 микросекунды;</li></ul><p>Да, каждый из методов теперь работал гораздо дольше, однако общий результат не изменился — оператор + по прежнему лидирует. Заметим так же, что разница во времени между третьим и четвёртым методом, как и ожидалось, пренебрежимо мала.</p><p>После этого я попробовал не объявлять переменные глобальными, а задавать их в теле метода, но на результаты это всё равно не повлияло. Разумеется, можно проводить ещё много разных опытов (например, попробовать сложить больше, чем две строки), однако этого уже достаточно, чтобы иметь примерное представление о скоростях работы различных способов сложения строк в языке Python.</p>]]></content:encoded>
    </item>
  </channel>
</rss>