PascalABC.NET официальный канал
Kanalga Telegram’da o‘tish
Официальный канал языка и системы программирования PascalABC.NET
Ko'proq ko'rsatish1 859
Obunachilar
-124 soatlar
-117 kun
-2630 kun
Postlar arxiv
Шестнадцатеричные литеральные константы
В PascalABC.NET для шестнадцатеричные литеральных констант используется префикс $.
Потерянное время никогда не найти снова
Прекрасная фраза, сказанная Бенджамином Франклином, зашифрована в этом сообщении.
Ну а мы наслаждаемся лаконичностью метода EachCount после фильтрации цифр.
#методика
Select и JoinToString для строк
Зашифровать что-то - школьников хлебом не корми.
А мы вспоминаем Select для изменения каждого символа строки и JoinToString для превращения последовательности символов назад в строку.
Ну и паттерн Chr(Ord(c)+1) для увеличения всех кодов на 1.
Расшифровка таких строк - особое удовольствие!
#методика
Метод Count для строк
В данной простой задаче исследуем со школьниками применение уже известных методов и операций к строкам.
Здесь интересно то, что для проверки, является ли буква гласной, мы создаём не список букв, а строку из гласных, и проверяем гласную на вхождение в эту строку.
Компактно, ёмко - ничего лишнего
#методика
Ввод чисел до маркера конца ввода
Классический образец кода для начинающих.
Вводятся числа до определенного числа. Надо их обработать. Само введенное число не учитывать.
Удобно пользоваться циклом while и первое число вводить до цикла.
#методика
Задачи на использование метода Zip
Приведем несколько задач, иллюстрирующих использование метода Zip, объединяющего несколько последовательностей в одну. Используются структурированные данные.
Задача 1. Изменение координат наблюдений
Дана последовательность наблюдений с координатами (X, Y). Нужно найти разницу координат между соседними наблюдениями и представить её в виде объектов с полями (DX, DY).
type Observation = auto class
X, Y: real;
end;
begin
// Исходные наблюдения
var observations := Seq(new Observation(0, 0), new Observation(1, 1), new Observation(3, 4), new Observation(6, 8));
// Вычисление разницы координат
var deltas := observations.Zip(observations.Skip(1),
(a, b) -> new class(DX := b.X - a.X, DY := b.Y - a.Y));
deltas.Println; // Вывод результата
end.
Задача 2. Объединение данных о сотрудниках
Даны две последовательности: сотрудники с именами и возрастом, а также их зарплаты. Требуется объединить эти данные в объекты с полями Name, Age и Salary.
type Employee = auto class
Name: string;
Age: integer;
end;
type Salary = auto class
Amount: real;
end;
begin
// Списки сотрудников и зарплат
var employees := Seq(new Employee('Alice', 25), new Employee('Bob', 30), new Employee('Charlie', 35));
var salaries := Seq(new Salary(2000.0), new Salary(2500.0), new Salary(3000.0));
// Объединение данных
var employeeData := employees.Zip(salaries,
(e, s) -> new class(e.Name, e.Age, Salary := s.Amount));
employeeData.Println; // Вывод результата
end.
Задача 3. Сводка по продажам
Даны данные о продажах товаров за два квартала. Требуется вычислить разницу продаж для каждого товара и представить её в виде объектов с полями ProductName, Q1Sales, Q2Sales и Difference.
type Sale = auto class
ProductName: string;
Quantity: integer;
end;
begin
// Продажи за два квартала
var q1Sales := Seq(new Sale('ProductA', 100), new Sale('ProductB', 200), new Sale('ProductC', 150));
var q2Sales := Seq(new Sale('ProductA', 120), new Sale('ProductB', 180), new Sale('ProductC', 160));
// Объединение данных и вычисление разницы
var summary := q1Sales.Zip(q2Sales,
(q1, q2) -> new class(q1.ProductName, Q1Sales := q1.Quantity, Q2Sales := q2.Quantity, Difference := q2.Quantity - q1.Quantity));
summary.Println; // Вывод результата
end.
Задача 4. Анализ рейтингов продуктов
Даны данные о рейтингах продуктов от двух разных покупателей. Требуется объединить эти данные и найти разницу между рейтингами.
type Rating = auto class
ProductName: string;
Score: integer;
end;
begin
// Рейтинги от двух покупателей
var ratings1 := Seq(new Rating('ProductA', 5), new Rating('ProductB', 3), new Rating('ProductC', 4));
var ratings2 := Seq(new Rating('ProductA', 4), new Rating('ProductB', 5), new Rating('ProductC', 3));
// Объединение данных и вычисление разницы
var differences := ratings1.Zip(ratings2,
(r1, r2) -> new class(r1.ProductName, Score1 := r1.Score, Score2 := r2.Score, Difference := r1.Score - r2.Score));
differences.Println; // Вывод результата
end.
Задача 5. Тренды в измерениях
Даны данные измерений, выполненных в два момента времени. Найдите разницу между значениями измерений.
type Measurement = auto class
Time: integer;
Value: real;
end;
begin
// Измерения в два момента времени
var measurements1 := Seq(new Measurement(0, 1.0), new Measurement(1, 2.5), new Measurement(2, 3.7));
var measurements2 := Seq(new Measurement(0, 1.2), new Measurement(1, 2.4), new Measurement(2, 3.8));
// Разница между измерениями
var trends := Zip(measurements1, measurements2,
(m1, m2) -> new class(m1.Time, Difference := m2.Value - m1.Value));
trends.Println; // Вывод результата
end.Множества в PascalABC.NET уже никогда не будут прежними
Начиная с версии 3.10.2 выражения вида [1,2,3] в PascalABC.NET трактуется по умолчанию как массив.
Данное поведение реализовано в последних версиях Delphi, что абсолютно правильно: использовать распространенную запись [1,2,3] для редко используемых встроенных множеств - расточительство!
Встроенные множества в PascalABC.NET остаются, но для их использования следует использовать переменные с явным объявлением типа. Таким образом, весь код на старом Паскале будет работать.
На скриншоте показано, в каких ситуациях запись в [...] трактуется как массив, а в каких - как множество.
Старый синтаксис литеральных массивов |1,2,3| сохранится, но объявляется устаревшим.
#новое
Инициализация датасета
В PascalABC.NET имеется ряд создающих функций, позволяющих просто создавать датасеты.
На скрине показано создание датасета в виде словаря, сопоставляющего ключам - заголовкам столбцов - данные в виде массивов строк. Используются создающая функция Dict, а также операция to для создания пары (Ключ, Значение).
Иллюстрируется также будущая возможность PascalABC.NET - массивы задаются в квадратных скобках.
Считывание из файла словаря списков
На скриншоте - программа из 4 строк, считывающая из файла словарь слов вместе с их переводами.
В файле информация хранится в том же виде, что и выводится:
(consider,[рассматривать,учитывать]) (proposal,[предложение,заявка]) (affect,[влиять,затрагивать]) (suggest,[предлагать,советовать,означать])
Директива компилятора {$DisableStandardUnits}
А хотите, чтобы в генерируемый код вообще не добавлялось ничего лишнего? Воспользуйтесь директивой {$DisableStandardUnits}
В итоге к генерируемому коду не будет добавлено ничего из стандартных модулей. Нельзя будет пользоваться ни Print, ни срезами, ни встроенными множествами. Зато генерируемый код будет крайне компактным и наиболее близким к тому, что генерирует компилятор C#.
Код данной dll занимает всего 3072 байт! А на C# так сможете?
{$DisableStandardUnits}
library LibA;
type
My = class
i,j: integer;
end;
function Add(a,b: integer) := a + b;
end.Нововведения в модуде Coords
В модуле Coords появились функции Distance, Middle и многое другое.
uses Coords;
begin
Globals.PointRadius := 2.3;
Globals.LineWidth := 1.0;
var p1 := Pnt(2,3);
var p2 := Pnt(-4,7.3);
var p3 := Pnt(-5,-3);
DrawPoint(p1);
DrawPoint(p2);
DrawPoint(p3);
DrawText(p1,'A', Align := Alignment.LeftBottom, Size := 18);
DrawText(p2,'B', Align := Alignment.LeftBottom, Size := 18);
DrawText(p3,'C', Align := Alignment.RightTop, Size := 18);
DrawLine(p1,p2);
DrawLine(p1,p3);
DrawLine(p2,p3);
DrawText(Middle(p1,p2), p1.Distance(p2).ToString(2), Align := Alignment.Center, BackgroundColor := Colors.LightBlue);
DrawText(Middle(p2,p3), p2.Distance(p3).ToString(2), Align := Alignment.Center,
BackgroundColor := Colors.White, BorderWidth := 0.5);
DrawText(Middle(p1,p3), p1.Distance(p3).ToString(2), Align := Alignment.Center, BackgroundColor := Colors.LightGreen);
end.
Скачайте новую версию!
#новое💡 Метод NWise в PascalABC.NET: анализ временных данных в несколько строк кода
Метод NWise в PascalABC.NET помогает разбивать последовательности на подгруппы фиксированной длины. Он возвращает последовательность массивов, где каждый массив содержит соседние элементы исходной последовательности. Это удобно для задач анализа временных данных, обработки текстов или любых последовательностей.
Пример работы:
var a := Arr(1, 2, 3, 4, 5, 6);
foreach var group in a.NWise(3) do
Println(group);
// Результат: [1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6]
📝 Примеры задач для анализа временных рядов:
1️⃣ Скользящее среднее температуры
Вычислим средние значения температуры за последние 3 дня:
var temperatures := Arr(22.1, 23.4, 21.8, 24.2, 22.9, 23.7);
foreach var window in temperatures.NWise(3) do
Println(window.Average.Round(4));
// Результат: 22.4333, 23.1333, 22.9667, 23.6
2️⃣ Обнаружение резких изменений
Найдем периоды, где изменения потребления электроэнергии превышают 50 кВт⋅ч:
var consumption := Arr(120, 180, 150, 200, 260, 220);
foreach var window in consumption.NWise(2) do
if Abs(window[1] - window[0]) > 50 then
Println(window);
// Результат: [120, 180], [200, 260]
3️⃣ Максимальная скорость ветра
Определим максимальную скорость ветра за каждые 3 часа:
var windSpeeds := Arr(5, 8, 6, 10, 12, 9, 7);
foreach var window in windSpeeds.NWise(3) do
Println(window.Max);
// Результат: 8, 10, 12, 12, 12
4️⃣ Суммирование данных в окнах
Подсчитаем общее количество запросов к серверу за каждые 4 часа:
var requests := Arr(50, 60, 70, 80, 90, 100, 110);
foreach var window in requests.NWise(4) do
Println(window.Sum);
// Результат: 260, 300, 340, 380
5️⃣ Выявление стабильных периодов
Найдем периоды, где изменения курса валют минимальны (разница между максимумом и минимумом в окне ≤ 1):
var exchangeRates := Arr(74.5, 74.6, 74.8, 74.7, 74.5, 74.4, 74.6);
foreach var window in exchangeRates.NWise(3) do
if window.Max - window.Min <= 1 then
Println(window);
// Результат: [74.6, 74.8, 74.7], [74.5, 74.4, 74.6]
6️⃣ Выявление трендов
Определим окна, где значения постоянно растут:
var sales := Arr(100, 120, 140, 130, 150, 160, 170);
foreach var window in sales.NWise(3) do
if (window[0] < window[1]) and (window[1] < window[2]) then
Println(window);
// Результат: [100, 120, 140], [130, 150, 160], [150, 160, 170]
⚡️ Используйте NWise, чтобы ускорить анализ временных рядов и упростить код! 🚀Отличия новых множеств
Одно из важнейших отличий новых множеств от старых - контроль выхода за границы типа.
Мы можем попытаться записать в set of byte значения, выходящие за границы, но получим исключение времени выполнения.
Новые множества
В PascalABC.NET обновлена реализация встроенных множеств set of T, просуществовавшая 17 лет. За это время в PascalABC.NET внесено огромное количество улучшений: появились обобщенные классы, перегрузка операций, методы расширения, реализация интерфейсов, последовательности. Именно благодаря этим средствам реализация новых множеств стала возможной.
В результате новые множества значительно ускорены, приближаясь по эффективности к HashSet<T>.
На скриншоте - программа, которая работает в старой версии примерно в 1000 медленнее.
Обновите Паскаль - скачайте новую версию!
#PascalABC #новое
begin
var s: set of integer;
var n := 10000000;
for var i:=1 to n do
s += [i];
Print(MillisecondsDelta);
end.Игра Животные
Создаем игру "Угадай животное" на PascalABC.NET
Хотите научить программу угадывать загаданные вами животные? В PascalABC.NET это легко реализовать с помощью бинарного дерева и сериализации. Покажем, как это сделать, на примере классической игры "Угадай животное".
Пример кода
type
[Serializable]
Node = auto class
Data: string; Yes, No: Node;
end;
const FName = 'animals.dat';
begin
var root: Node;
Println('Загадайте животное');
if not FileExists(FName) then
root := new Node('Собака', nil, nil)
else root := Node(Deserialize(FName));
var cur := root;
while cur.Yes <> nil do
if ReadlnInteger(cur.Data + '? (0-Нет, 1-Да):') = 1 then
cur := cur.Yes else cur := cur.No;
if ReadlnInteger('Это ' + cur.Data + '? (0-Нет, 1-Да):') = 1 then
Println('Я угадала!')
else
begin
var newA := ReadlnString('Я проиграла. Какое животное вы загадали?');
var quest := ReadlnString('Введите вопрос для отличия ' +
newA + ' от ' + cur.Data + ':');
cur.Yes := new Node(newA, nil, nil);
cur.No := new Node(cur.Data, nil, nil);
cur.Data := quest;
end;
Serialize(FName, root);
end.
Что делает этот код?
🔹 Создание дерева знаний: узлы дерева содержат либо вопрос, либо название животного.
🔹 Интерактивный процесс угадывания: программа задает вопросы до тех пор, пока не достигнет конца дерева.
🔹 Добавление новых знаний: если программа ошибается, она добавляет новое животное и соответствующий вопрос в дерево.
🔹 Сохранение прогресса: данные сохраняются в файл, что позволяет программе "учиться" даже после закрытия.
Как это работает на практике?
🔹 Если вы играете впервые, программа начнет с единственного узла — "Собака".
🔹 Постепенно дерево знаний будет разрастаться: каждая ошибка добавляет новый вопрос и новый узел.
🔹 Благодаря сериализации, данные сохраняются между сессиями.
Почему это интересно?
🔹 Обучение на практике: игра демонстрирует, как устроены деревья и как их можно использовать.
🔹 Простота расширения: можно добавить сохранение статистики, визуализацию дерева или использование синонимов.
Попробуйте реализовать эту игру и удивите своих друзей — пусть они проверят, как "умна" ваша программа! 🚀
Ниже - интерактивная версия нашей игры на JavaScript
https://claude.site/artifacts/923ab4f7-5d10-4db2-a227-bc74d699419eРабота с индексами элементов в матрице
В PascalABC.NET работа с матрицами становится особенно удобной благодаря встроенным методам. Хотите найти все позиции элементов, удовлетворяющих определённому условию? А может, сразу обновить значения? Давайте рассмотрим это на примере:
begin
var a := MatrRandom(3,4,0,2); // Создаём случайную матрицу 3x4 с элементами от 0 до 2
a.Println(3); // Выводим матрицу в удобном формате
a.Indices(x -> x = 0).Println; // Находим индексы всех нулей в матрице
a.Indices(x -> x = 0).ForEach(\(i,j) -> (a[i,j] := 99)); // Заменяем все нули на 99
a.Println(3); // Выводим обновлённую матрицу
end.
🔍 Что здесь происходит?
🔹 Генерация матрицы: С помощью MatrRandom создаём матрицу 3x4 со случайными числами от 0 до 2.
🔹 Поиск индексов: Метод Indices возвращает все позиции элементов, соответствующих условию. В данном случае мы ищем нули.
🔹 Обновление значений: Метод ForEach позволяет перебрать пары индексов (i, j) и изменить значения в матрице — нули заменяются на 99.
📈 Зачем это нужно? Такой подход удобен для сложных вычислений, анализа данных, обработки изображений, где нужно находить и модифицировать элементы по условию. Сжатый и выразительный код позволяет быстрее решать задачи!
Попробуйте использовать матрицы и методы работы с индексами в своих проектах, и вы увидите, насколько это упрощает вашу жизнь программиста! 🚀Оптимизация поиска простых чисел: Решето Эратосфена в PascalABC.NET
Решето Эратосфена — это один из наиболее эффективных алгоритмов для нахождения всех простых чисел до заданного предела n. Он отличается высокой производительностью и простотой реализации.
Алгоритм обладает асимптотической сложностью O(n * log(log n)), что делает его значительно быстрее простейших методов определения простоты через деление.
function SieveOfEratosthenes(n: integer): array of integer;
begin
var isPrime := |True| * (n + 1);
isPrime[0] := False;
isPrime[1] := False;
for var i := 2 to Trunc(Sqrt(n)) do
if isPrime[i] then
for var j := i * i to n step i do
isPrime[j] := False;
Result := (2..n).Where(i -> isPrime[i]).ToArray;
end;
begin
var n := 50;
var primes := SieveOfEratosthenes(n);
Println('Простые числа до ', n, ': ', primes);
end.
Этот пример демонстрирует, как эффективно можно реализовать решето Эратосфена в PascalABC.NET. Для визуализации работы алгоритма и лучшего понимания его процесса, вы можете ознакомиться с интерактивной демонстрацией по ссылке: визуализация решета Эратосфена, любезно сгенерированной Claude.ai по коду, приведенному выше/
Использование этого алгоритма позволяет не только быстро находить простые числа, но и закладывает основу для разработки более сложных алгоритмов в области теории чисел и криптографии.Гарри Поттер - самые частые слова в начале предложения
Разбиваем текст на предложения, а затем предложения - на слова. Слова добавляем в список, затем по ним составляем частотный словарь и сортируем его по встречаемости.
begin
// LordOfTheRings
var sentences := ReadAllText('HarryPotter.txt').ToWords('.?!');
var lst := new List<string>;
foreach var sentence in sentences do
begin
var words := sentence.ToWords(AllDelimiters);
if words.Length = 0 then
continue;
if words[0][1].IsLower then
continue;
lst.Add(words[0]);
end;
lst.EachCount.OrderByDescending(kvp -> kvp.Value).Take(30).Print;
end.Сортировка столбцов матрицы по возрастанию суммы в столбце
Метод a.Cols и функция MatrByCol превращают матрицу в массив массивов по столбцам и наоборот. В промежутке можно выполнить любую операцию со столбцами - например, отсортировать их по некоторому критерию.
begin
var a := MatrRandomInteger(3,4,1,9);
a.Println;
a := MatrByCol(a.Cols.OrderBy(col -> col.Sum));
a.Println;
end.
Аналогичный код на Python требует подключения numpy:
import numpy as np
a = np.random.randint(0, 100, (3, 4))
print(a)
sorted_indices = np.argsort(a.sum(axis=0))
sorted_matrix = a[:, sorted_indices]
print(sorted_matrix)📌 Группировка элементов с использованием словаря в PascalABC.NET 📌
В PascalABC.NET есть стандартный метод GroupBy, который позволяет группировать данные по ключу в одну строку. Но сегодня мы покажем, как организовать подобный процесс вручную, что помогает глубже понять, как работает группировка и какие структуры данных задействованы.
👀 Что делает этот код?
🔹 Имеется список пар элементов с категориями, например, фрукт, овощ, ягода.
🔹 Код создаёт словарь grouped, где ключами являются категории, а значениями — списки элементов в каждой категории.
🔹 Для каждого элемента проверяется наличие категории в словаре:
✦ Если категория отсутствует, создаётся новая запись со списком.
✦ Элемент добавляется в соответствующий список.
🔹 В результате формируется структура данных, аналогичная результату GroupBy, но построенная вручную.
✨ Почему это полезно?
Такой пример не только помогает понять принцип работы GroupBy, но и показывает, как можно использовать словари для создания сложных структур данных. Подход может быть полезен в ситуациях, где требуется больше контроля над логикой группировки.
Пример кода:
begin
var items := |('яблоко','фрукт'), ('помидор','овощ'), ('банан','фрукт')
, ('морковь','овощ'), ('арбуз','ягода')|;
var grouped := new Dictionary<string, List<string>>;
foreach var (item,category) in items do
begin
if category not in grouped then
grouped[category] := new List<string>;
grouped[category].Add(item)
end;
grouped.PrintLines;
end.
📊 Результат:
фрукт: яблоко, банан овощ: помидор, морковь ягода: арбузПопробуйте разобраться в устройстве GroupBy на этом примере — это важный шаг в понимании основ алгоритмов и структур данных! #Группировка #Словарь #GroupBy
