diff --git a/course-2021-1/exercises/01-primitive-types/Numbers.Tests/FloatNumbersTests.cs b/course-2021-1/exercises/01-primitive-types/Numbers.Tests/FloatNumbersTests.cs
index b0884a56..ade588ea 100644
--- a/course-2021-1/exercises/01-primitive-types/Numbers.Tests/FloatNumbersTests.cs
+++ b/course-2021-1/exercises/01-primitive-types/Numbers.Tests/FloatNumbersTests.cs
@@ -22,4 +22,4 @@ public void Test_GetNaN_IsNaNOfGetNaNReturnsTrue()
Assert.True(FloatNumbers.IsNaN(FloatNumbers.GetNaN()));
}
}
-}
+}
\ No newline at end of file
diff --git a/course-2021-1/exercises/01-primitive-types/Numbers.Tests/Numbers.Tests.csproj b/course-2021-1/exercises/01-primitive-types/Numbers.Tests/Numbers.Tests.csproj
index 8a03330f..46553a6a 100644
--- a/course-2021-1/exercises/01-primitive-types/Numbers.Tests/Numbers.Tests.csproj
+++ b/course-2021-1/exercises/01-primitive-types/Numbers.Tests/Numbers.Tests.csproj
@@ -1,7 +1,7 @@
- netcoreapp2.0
+ netcoreapp3.1
false
diff --git a/course-2021-1/exercises/01-primitive-types/Numbers/FloatNumbers.cs b/course-2021-1/exercises/01-primitive-types/Numbers/FloatNumbers.cs
index 9cb1d053..24bfbb28 100644
--- a/course-2021-1/exercises/01-primitive-types/Numbers/FloatNumbers.cs
+++ b/course-2021-1/exercises/01-primitive-types/Numbers/FloatNumbers.cs
@@ -3,6 +3,7 @@
*/
using System;
+using System.Reflection.Metadata.Ecma335;
namespace Numbers
{
@@ -17,7 +18,8 @@ internal static double GetNaN()
Необходимо вернуть значение, не используя непосредственно саму константу.
Для этого подумай, какой смысл в себе несет эта константа и где бы она могла стать результатом операции или вычисления функции.
*/
- throw new NotImplementedException();
+ //throw new NotImplementedException();
+ return 0.0 / 0;
}
///
@@ -28,20 +30,34 @@ internal static double GetNaN()
internal static bool IsNaN(double d)
{
// Подсказка: по аналогии с константами типа int, у типа double тоже есть свой набор констант.
- throw new NotImplementedException();
+ //throw new NotImplementedException();
+ return double.IsNaN(d);
}
-
+
///
/// Возвращает результат сравнения двух вещественнозначных чисел.
///
/// -1 - первое меньше второго, 0 - значения равны, 1 - первое больше второго.
- internal static int Compare(/* дополни сигнатуру метода как считаешь правильным */)
+ internal static int Compare(double a, double b, double eps)
{
/*
Подумай, почему это задание дано в части про вещественнозначные числа. И почему не дана полная сигнатура метода.
Если сходу идей нет, перестань искать подвох и просто реализуй дословно. Теперь еще раз посмотри на код и подумай в чем может быть проблема, сколько должно быть аргументов.
*/
- throw new NotImplementedException();
+ //throw new NotImplementedException();
+ if (b - a < eps)
+ {
+ if (a - b < eps)
+ {
+ return 0;
+ }
+ else
+ {
+ return 1;
+ }
+ }
+
+ return -1;
}
// и все?!! О_о
@@ -49,4 +65,4 @@ internal static int Compare(/* дополни сигнатуру метода к
// и все... -_-
}
-}
+}
\ No newline at end of file
diff --git a/course-2021-1/exercises/01-primitive-types/Numbers/Integers.cs b/course-2021-1/exercises/01-primitive-types/Numbers/Integers.cs
index b1d90398..7af18ee2 100644
--- a/course-2021-1/exercises/01-primitive-types/Numbers/Integers.cs
+++ b/course-2021-1/exercises/01-primitive-types/Numbers/Integers.cs
@@ -41,12 +41,7 @@ public static class Integers
///
internal static int HalfIntMaxValue()
{
- /*
- После C++ вы будете приятно удивлены какое умное в .Net автодополнение (IntelliSense).
- Особенно это касается связки Visual Studio + Resharper, используя которую, если просто набрать return и нажать пробел,
- то в появившемся списке автодополнения одной из первых будет нужная тебе константа :)
- */
- throw new NotImplementedException();
+ return Int32.MaxValue / 2;
}
///
@@ -54,8 +49,7 @@ internal static int HalfIntMaxValue()
///
internal static int Cube(int x)
{
- // не сомневайся, пиши. Тут без подвохов.
- throw new NotImplementedException();
+ return x * x * x;
}
///
@@ -63,11 +57,7 @@ internal static int Cube(int x)
///
internal static int CubeWithOverflowCheck(int x)
{
- /*
- Если спал на лекции, то тут придется погуглить, сорри.
- И заодно подумай какой режим выставлен по умолчанию. Почему. И почему категорически нельзя надеяться на режим по умолчанию.
- */
- throw new NotImplementedException();
+ return checked(x * x * x);
}
///
@@ -75,8 +65,7 @@ internal static int CubeWithOverflowCheck(int x)
///
internal static int CubeWithoutOverflowCheck(int x)
{
- // если сделал предыдущие, то с этим уже должно быть понятно.
- throw new NotImplementedException();
+ return unchecked(x * x * x);
}
///
@@ -86,14 +75,7 @@ internal static int CubeWithoutOverflowCheck(int x)
/// Эквивалентное строковое представление числа.
internal static string ToString(int x)
{
- /*
- Возможно ты уже в курсе, что "эквивалентное ему строковое представление" - понятие очень расплывчатое, и существует
- огромная куча различных форматов вывода чисел: "123456789", "123 456 789", "0123456789" и т.п.
- Сейчас представим, что такой проблемы не существует, и выберем самый простой вариант, который использует какие-то дефолтные настройки.
-
- Подсказка: нужно воспользоваться методом, который есть у абсолютно всех объектов.
- */
- throw new NotImplementedException();
+ return x.ToString();
}
///
@@ -103,11 +85,7 @@ internal static string ToString(int x)
/// 32-битное знаковое целочисленное представление числа.
internal static int Parse(string s)
{
- /*
- Продолжай идти простым путем -нужен метод, обратный методу ToString выше, который распарсит дефолтное строковое представление числа.
- Подсказка: у каждого примитивного типа есть набор статических методов, среди которых есть нужный.
- */
- throw new NotImplementedException();
+ return Int32.Parse(s);
}
///
@@ -115,11 +93,7 @@ internal static int Parse(string s)
///
internal static int TenTimes(int x)
{
- /*
- Реализуй умножение числа на 10 без использования арифметических операций над числами.
- Воспользуйся реализованными выше методами ToString и Parse. И не думай ни о каких переполнениях - задача не на это :)
- */
- throw new NotImplementedException();
+ return Int32.Parse(x.ToString() + "0");
}
///
@@ -129,15 +103,7 @@ internal static int TenTimes(int x)
/// Эквивалентное строковое представление в шестнадцатиричной системе счисления.
internal static string ToHexString(int x)
{
- /*
- У метода ToString числовых типов есть перегрузка, которая принимает строку с одним из заданного набора форматов.
- В студии дается хорошая и понятная подсказка с этим набором форматов, в других же IDE скорее всего такого не будет, и придется погуглить форматы.
- */
- throw new NotImplementedException();
+ return x.ToString("X");
}
-
- /*
- Закончил? Переходи в FloatNumbers.cs
- */
}
-}
+}
\ No newline at end of file
diff --git a/course-2021-1/exercises/01-primitive-types/Numbers/Numbers.csproj b/course-2021-1/exercises/01-primitive-types/Numbers/Numbers.csproj
index ce1697ae..c73e0d16 100644
--- a/course-2021-1/exercises/01-primitive-types/Numbers/Numbers.csproj
+++ b/course-2021-1/exercises/01-primitive-types/Numbers/Numbers.csproj
@@ -2,7 +2,7 @@
Exe
- netcoreapp2.0
+ netcoreapp3.1
diff --git a/course-2021-1/exercises/01-primitive-types/Numbers/Program.cs b/course-2021-1/exercises/01-primitive-types/Numbers/Program.cs
index 78460c01..6a42c948 100644
--- a/course-2021-1/exercises/01-primitive-types/Numbers/Program.cs
+++ b/course-2021-1/exercises/01-primitive-types/Numbers/Program.cs
@@ -21,4 +21,4 @@ private static void Main()
Console.WriteLine("Hello World!");
}
}
-}
+}
\ No newline at end of file
diff --git a/course-2021-1/exercises/02-adventure-time/AdventureTime/AdventureTime/Time.cs b/course-2021-1/exercises/02-adventure-time/AdventureTime/AdventureTime/Time.cs
index 45de70d1..9bbe44ef 100644
--- a/course-2021-1/exercises/02-adventure-time/AdventureTime/AdventureTime/Time.cs
+++ b/course-2021-1/exercises/02-adventure-time/AdventureTime/AdventureTime/Time.cs
@@ -1,4 +1,5 @@
using System;
+using System.Globalization;
using NodaTime;
using NodaTime.TimeZones;
@@ -14,7 +15,7 @@ internal static class Time
///
public static DateTime WhatTimeIsIt()
{
- throw new NotImplementedException();
+ return DateTime.Now;
}
///
@@ -22,7 +23,7 @@ public static DateTime WhatTimeIsIt()
///
public static DateTime WhatTimeIsItInUtc()
{
- throw new NotImplementedException();
+ return DateTime.UtcNow;
}
///
@@ -33,10 +34,7 @@ public static DateTime WhatTimeIsItInUtc()
/// Объект с заданными временем и значением .
public static DateTime SpecifyKind(DateTime dt, DateTimeKind kind)
{
- /*
- Подсказка: поищи в статических методах DateTime.
- */
- throw new NotImplementedException();
+ return DateTime.SpecifyKind(dt, kind);
}
///
@@ -46,12 +44,7 @@ public static DateTime SpecifyKind(DateTime dt, DateTimeKind kind)
/// Строковое представление времени в формате ISO 8601.
public static string ToRoundTripFormatString(DateTime dt)
{
- /*
- Обязательно поиграйся и посмотри на изменение результата в зависимости от dt.Kind (для этого тебе поможет метод выше).
- Ну и на будущее запомни этот прекрасный строковый формат представления времени - он твой бро!
- Название запоминать не нужно, просто помни, что для передачи значения в виде строки, выбирать лучше инвариантные относительно сериализации/десериализации форматы.
- */
- throw new NotImplementedException();
+ return dt.ToString("O");
}
///
@@ -61,11 +54,7 @@ public static string ToRoundTripFormatString(DateTime dt)
/// Объект .
public static DateTime ParseFromRoundTripFormat(string dtStr)
{
- /*
- Поиграйся и проверь, что round-trip действительно round-trip, т.е. туда-обратно равно оригиналу (для туда воспользуйся предыдущим методом).
- Проверь для всех значений DateTime.Kind.
- */
- throw new NotImplementedException();
+ return DateTime.Parse(dtStr, null, DateTimeStyles.RoundtripKind);
}
///
@@ -73,11 +62,7 @@ public static DateTime ParseFromRoundTripFormat(string dtStr)
///
public static DateTime ToUtc(DateTime dt)
{
- /*
- Eсли воспользуешься нужным методом, то напоминаю, что результат его работы зависит от dt.Kind.
- В случае dt.Kind == Unspecified предполагается, что время локальное, т.е. результат работы в случае Local и Unspecified совпадают. Такие дела
- */
- throw new NotImplementedException();
+ return dt.ToUniversalTime();
}
///
@@ -87,8 +72,7 @@ public static DateTime ToUtc(DateTime dt)
/// Время, передвинутое вперед на 10 секунд от заданного
public static DateTime AddTenSeconds(DateTime dt)
{
- // здесь воспользуйся методами самого объекта и заодно посмотри какие еще похожие есть
- throw new NotImplementedException();
+ return dt.AddSeconds(10);
}
///
@@ -98,11 +82,7 @@ public static DateTime AddTenSeconds(DateTime dt)
/// Время, передвинутое вперед на 10 секунд от заданного
public static DateTime AddTenSecondsV2(DateTime dt)
{
- /*
- Ну а здесь воспользуйся сложением с TimeSpan. Обрати внимание, что помимо конструктора, у класса есть набор полезных статических методов-фабрик.
- Обрати внимание, что у TimeSpan нет статических методов FromMonth, FromYear. Как думаешь, почему?
- */
- throw new NotImplementedException();
+ return dt + TimeSpan.FromSeconds(10);
}
///
@@ -113,12 +93,7 @@ public static DateTime AddTenSecondsV2(DateTime dt)
/// Полное количество часов заданного временного отрезка.
public static int GetHoursBetween(DateTime dt1, DateTime dt2)
{
- /*
- 1) Подумай, в чем разница между Hours и TotalHours
- 2) Проверь, учитывается ли Kind объектов при арифметических операциях.
- 3) Подумай, почему возвращаемое значение может отличаться от действительности.
- */
- throw new NotImplementedException();
+ return (int) (dt2 - dt1).TotalHours;
}
///
@@ -126,8 +101,7 @@ public static int GetHoursBetween(DateTime dt1, DateTime dt2)
///
public static int GetTotalMinutesInThreeMonths()
{
- // ну тут все просто и очевидно, если сделал остальные и подумал над вопросами в комментах.
- throw new NotImplementedException();
+ return (int) TimeSpan.FromDays(91).TotalMinutes;
}
#region Adventure time saga
@@ -141,13 +115,9 @@ public static int GetTotalMinutesInThreeMonths()
///
public static int GetAdventureTimeDurationInMinutes_ver0_Dumb()
{
- /*
- Как ты понимаешь, время выбрано не просто так, но для начала давай прикинемся совсем наивными.
- Лондон находится в часовом поясе +0 (GMT), а Москва в +3 (MSK). Воспользуйся DateTimeOffset, чтобы задать правильное время, и посчитай разницу в минутах. Посмотри на результат.
- Держи, заготовочку для копипасты:
- - 2010, 3, 28, 2, 15, 0
- */
- throw new NotImplementedException();
+ var mskDate = new DateTimeOffset(2010, 3, 28, 2, 15, 0, TimeSpan.FromHours(3));
+ var gmtDate = new DateTimeOffset(2010, 3, 28, 2, 15, 0, TimeSpan.Zero);
+ return (int) (gmtDate - mskDate).TotalMinutes;
}
///
@@ -160,12 +130,9 @@ public static int GetAdventureTimeDurationInMinutes_ver0_Dumb()
///
public static int GetGenderSwappedAdventureTimeDurationInMinutes_ver0_Dumb()
{
- /*
- Здесь то же самое. Сорри, немного бездумного кодинга. Вот заготовочка для копипасты времени:
- - 2010, 3, 28, 3, 15, 0
- - 2010, 3, 28, 1, 15, 0
- */
- throw new NotImplementedException();
+ var mskDate = new DateTimeOffset(2010, 3, 28, 3, 15, 0, TimeSpan.FromHours(3));
+ var gmtDate = new DateTimeOffset(2010, 3, 28, 1, 15, 0, TimeSpan.Zero);
+ return (int) (gmtDate - mskDate).TotalMinutes;
}
///
@@ -173,39 +140,26 @@ public static int GetGenderSwappedAdventureTimeDurationInMinutes_ver0_Dumb()
///
public static int GetAdventureTimeDurationInMinutes_ver1_FeelsSmarter()
{
- /*
- Глава вторая, в которой оказывается, что в некоторых странах принята такая штука как летнее время (не совсем то, про которое поет Лана Дель Рей).
-
- Внимательный читатель мог усомниться в данных мной часовых поясах и их смещении относительно UTC и был бы прав.
- На самом деле смещения таковы: Лондон +1 (BST - British Summer Time), Москва +4 (MSD - Moscow Daylight Time).
- Давай теперь учтем правильное смещение. Я понимаю, что это очевидно, что результат не изменится, но тебе же не сложно скопипастить и просто поменять смещения?
- */
- throw new NotImplementedException();
+ var msdDate = new DateTimeOffset(2010, 3, 28, 2, 15, 0, TimeSpan.FromHours(4));
+ var bstDate = new DateTimeOffset(2010, 3, 28, 2, 15, 0, TimeSpan.FromHours(1));
+ return (int) (bstDate - msdDate).TotalMinutes;
}
- // GetGenderSwappedAdventureTimeDurationInMinutes_ver1_FeelsSmarter опустим, там то же самое
-
///
/// Возвращает количество минут, проведенных в пути из Москвы в Лондон.
///
public static int GetAdventureTimeDurationInMinutes_ver2_FeelsLikeRocketScience()
{
- /*
- Глава третья и последняя, в которой внезапно оказывается, что Финн и Фионна находятся в суперпозиции и существуют в виде гендерно нейтрального сверхчеловека, который и путешествовал из Москвы в Лондон.
-
- Дело в том, что перевод на летнее время в 2010м году в Москве произошел в 02:00 (стрелки часов перевели на час вперед), а в Лондоне - в 01:00.
- Таким образом в Москве не было 02:15 - однако можно, например, считать, что этому времени соответствует 03:15. Ну а в Лондоне 01:15 это на самом деле 02:15.
- Только как это обработать в рамках класса DateTimeOffset? Да, для конкретного примера мы могли бы сами ручками "перевести стрелки" и поставить правильное время, но что делать в общем случае?
- Тут придется воспользоваться знанием о часовых поясах. Их есть у .Net.
-
- Дабы ты не мучился[-ась], роя в недрах msdn и stackoverflow в поисках ответа (в конце концов, когда тебе это в жизни действительно понадобится),
- ниже ты найдешь готовый метод GetZonedTime. Просто посмотри на него (можешь даже посмотреть методы и свойства типа TimeZoneInfo, если интересно) и воспользуйся им для вычисления правильного времени
- "отбытия" и "прибытия" наших героев. Затем посчитай длительность путешествия. Также даны правильные идентификаторы зон.
- */
const string moscowZoneId = "Russian Standard Time";
const string londonZoneId = "GMT Standard Time";
- throw new NotImplementedException();
+ // на Mac OS зоны обозначаются по-другому
+ const string moscowZoneIdLinux = "Europe/Moscow";
+ const string londonZoneIdLinux = "Europe/London";
+
+ var mskDate = GetZonedTime(new DateTime(2010, 3, 28, 2, 15, 0), moscowZoneIdLinux);
+ var gmtDate = GetZonedTime(new DateTime(2010, 3, 28, 2, 15, 0), londonZoneIdLinux);
+ return (int) (gmtDate - mskDate).TotalMinutes;
}
///
@@ -213,12 +167,16 @@ public static int GetAdventureTimeDurationInMinutes_ver2_FeelsLikeRocketScience(
///
public static int GetGenderSwappedAdventureTimeDurationInMinutes_ver2_FeelsLikeRocketScience()
{
- /*
- Реши по аналогии с предыдущим методом и проверь, что оба метода действительно возвращают одно и то же время (и что оно правильное).
- */
const string moscowZoneId = "Russian Standard Time";
const string londonZoneId = "GMT Standard Time";
- throw new NotImplementedException();
+
+ // на Mac OS зоны обозначаются по-другому
+ const string moscowZoneIdLinux = "Europe/Moscow";
+ const string londonZoneIdLinux = "Europe/London";
+
+ var msdDate = GetZonedTime(new DateTime(2010, 3, 28, 3, 15, 0), moscowZoneIdLinux);
+ var bstDate = GetZonedTime(new DateTime(2010, 3, 28, 1, 15, 0), londonZoneIdLinux);
+ return (int) (bstDate - msdDate).TotalMinutes;
}
private static DateTimeOffset GetZonedTime(DateTime localTime, string timeZoneId)
@@ -277,7 +235,7 @@ private static ZonedDateTime GetZonedTime(LocalDateTime localTime, string timeZo
/// True - если родились в один день, иначе - false.
internal static bool AreEqualBirthdays(DateTime person1Birthday, DateTime person2Birthday)
{
- throw new NotImplementedException();
+ return person1Birthday.Month == person2Birthday.Month && person1Birthday.Day == person2Birthday.Day;
}
}
-}
+}
\ No newline at end of file
diff --git a/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector/Vector.cs b/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector/Vector.cs
index bb9db585..32e62a1b 100644
--- a/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector/Vector.cs
+++ b/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector/Vector.cs
@@ -1,193 +1,160 @@
using System;
+using System.Runtime.CompilerServices;
+
+[assembly: InternalsVisibleTo("BoringVector.Tests")]
namespace BoringVector
{
- #region 1. Структура Vector
-
- /*
- Реализуй структуру Vector - см. комментарии внутри нее.
- */
-
- internal struct Vector
+ ///
+ /// Класс для работы с векторами на плоскости
+ ///
+ internal readonly struct Vector
{
- /*
- Vector задается парой вещественных координат X и Y.
- */
-
-
- /*
- На месте заглушек добавь реализацию базовых методов вектора:
- - квадрат длины
- - сумма векторов
- - умножение на коэффициент
- - скалярное произведение
- - векторное произведение (= площадь параллелограмма)
- */
+ public readonly double X;
+ public readonly double Y;
+ ///
+ /// Конструирует вектор из двух координат
+ ///
+ /// Координата по оси x
+ /// Координата по оси y
+ public Vector(double x, double y)
+ {
+ X = x;
+ Y = y;
+ }
+
+ ///
+ /// Возвращает , квадрат длины вектора
+ ///
+ /// , квадрат длины вектора
public double SquareLength()
{
- throw new NotImplementedException();
+ return X * X + Y * Y;
}
+
+ ///
+ /// Возвращает сумму текущего и заданного
+ ///
+ /// Прибавляемый
+ /// , сумма векторов
public Vector Add(Vector v)
{
- throw new NotImplementedException();
+ return new Vector(X + v.X, Y + v.Y);
}
+
+ ///
+ /// Возвращает , умноженный на число
+ ///
+ /// , коэффициент умножения
+ /// , умноженный на число
public Vector Scale(double k)
{
- throw new NotImplementedException();
+ return new Vector(k * X, k * Y);
}
+
+ ///
+ /// Возвращает , скалярное произведение с заданным
+ ///
+ /// , на который умножается текущий
+ /// , скалярное произведение с заданным
public double DotProduct(Vector v)
{
- throw new NotImplementedException();
+ return X * v.X + Y * v.Y;
}
+
+ ///
+ /// Возвращает , модуль векторного произведения с заданным
+ ///
+ /// , на который умножается текущий
+ /// , модуль векторного произведения с заданным
public double CrossProduct(Vector v)
{
- throw new NotImplementedException();
+ return Math.Abs(X * v.Y - Y * v.X);
}
-
- /*
- Переопредели ниже метод ToString - пусть выводит (X; Y)
- */
-
- #region operators
-
- /*
- Реализуй также следущие операторы (Vector v, u и double k):
- - v + u, v - u
- - k * v, v * k, v / k
- - +v, -v
- */
-
- #endregion
- }
-
- #endregion
-
- /*
- Время отправиться в VectorExtensions.cs за новой порцией квестов, герой!
- Как закончишь, возвращайся за щедрым вознаграждением!
- */
-
-
- #region 3. Комментарии
-
- /*
- Прости, я соврал. К сожалению, пока ты делал(-а) вторую часть, человек, который понимал, о чем идет речь в первой части,
- успел съездить в путешествие под названием "во все тяжкие" и теперь проходит курс реабилитации. А те, кто был хотя бы примерно в теме,
- внезапно лишились рассудка.
- Тут еще из будущего сообщили, что тебе дали задачу поинтереснее, и ты наотрез отказался(-ась) сотрудничать в передаче знаний.
- Ну а вместо тебя на эту задачу взяли пушистого котика, который отказывается разбираться в коде и уж тем более его писать - говорит у него лапки.
-
- В такой ситуации единственно возможное решение задачи - оставить после себя комментарии. Такие, чтобы даже котику было понятно!
- В общем, впереди неприятная для многих часть - необходимо добавить комментарии ко всем введенным типам, методам и свойствам :)
-
-
- _Хозяйке на заметку_
-
- Для многих это действительно довольно неприятная и скучнейшая часть - писать комментарии к коду. Проблема в том,
- что это еще и не так просто как кажется на первый взгляд. Очень желательно выдерживать единый стиль, писать по существу,
- писать не "для текущего разобравшегося в проблеме и предметной области себя", а для "того парня", "себя через год". Ну или пушистого котика.
-
- Есть и хорошее в этом деле. Комментирование кода очень похоже на написание автотестов - оно позволяет взглянуть
- на задачу и ее решение немного с другой стороны. Например, если слова не вяжутся, и не получается написать простое и короткое
- описание к методу или типу - это хороший сигнал, что он "с душком", и его стоит переделать/отрефакторить.
- Я лично чаще пишу комментарии ближе к концу работы над задачей. Это позволяет мне еще раз просмотреть весь написанный код под
- слегка иным углом обзора и самому сделать первичный code review.
-
-
- Ты мог(-ла) заметить, что в предыдущих заданиях для комментариев я использовал немного необычный синтаксис:
-
- ///
- /// Возвращает объект с заданными временем и значением .
- ///
- /// Объект , задающий время.
- /// Значение , задающий соответствующее свойство возвращаемого объекта.
- /// Объект с заданными временем и значением .
-
- Такой блок является комментарием, т.к. каждая строка начинается с //, но имеет свою внутреннюю структуру и синтаксис.
- Это так называемые Xml documentation comments. Их поддерживает сам компилятор. Они позволяют писать чуть более умные и продвинутые комментарии к сущностям,
- а потом, например, автоматически генерировать по ним красивую документацию.
- Правилом хорошего тона считается писать комментарии к методам, классам и другим сущностям, используя данный синтаксис - так ты и комментируешь их, и документируешь.
- Внутри методов он не поддерживается, поэтому там только обычные (// или /*).
-
- Ниже приведены примеры простейших комментариев. Если наведете мышкой на название метода DoNothing, увидишь,
- что студия отображает комментарий в подписи (в других IDE из коробки без плагинов это вряд ли будет работать).
- Если навести на аргумент метода DoNothing - something, увидишь комментарий к нему.
- Наведи теперь на NotImplementedException() - комментарий во всплывашке сделан с помощью такого же синтаксиса.
- Код .Net Framework задокументирован именно таким синтаксисом.
-
- Чтобы создать такой комментарий, не нужно писать разметку целиком самому. Если ввести ///, студия сама создаст нужные блоки.
-
- Плюсы Xml documentation comments:
- - блок комментариев имеет четкую предзаданную структуру, что дает возможность воспользоваться различными инструментариями
- автогенерации документации (и создавать, например, документацию вроде MSDN).
- В последней лабе мы, надеюсь, научимся генерировать для web api страничку с документацией к нашему апи и увидим, что генератор в том числе
- может для каждого метода апи создавать формочку для его проверки и ручного тестирования.
- - IDE может показывать ее в чуть более удобном виде, нежели если бы ты писал(-а) их обычным способом.
- Например, показывать во всплывающей подсказке только самое необходимое короткое описание, а длинное с пояснениями и примерами кода не показывать.
- - все названия типов, методов и свойств можно задавать в виде ссылки, например, , и это
- будет строгая, проверяемая компилятором, ссылка. Ты, думаю, помнишь, что компилятор как сервис в частности предоставляет разные возможности рефакторинга,
- например, переименование. Так вот, если воспользоваться им и переименовать метод DotProduct у структуры Vector, то
- переименуется и текст в ссылке. Если же ссылка указывает на невалидную сущность, то студия явно даст понять: "Cannot resolve symbol 'blah-blah-blah'".
- Я лично не проверял, но по идее можно даже сделать так, чтобы в таком случае была ошибка компиляции. В генерируемой же документации эти ссылки будут
- заменены на реальные ссылки на страницы описания соответствующей сущности, что довольно удобно для навигации по ней.
-
- */
-
- ///
- /// Класс, не делающий ничего.
- ///
- internal class Foo
- {
+
///
- /// Не делает ничего, как и подобает методам данного класса.
+ /// Возвращает , строковое представление
///
- /// Экземпляр чего бы то ни было.
- public static void DoNothing(object something)
+ /// Строковое представление
+ public override string ToString()
{
- // nothing to do here
+ return string.Concat("(", X.ToString(), "; )", Y.ToString(), ")");
}
-
- public static void ThrowNotImplementedException()
+
+ ///
+ /// Складывает два объекта и возвращает новый
+ ///
+ /// , левое слагаемое
+ /// , правое слагаемое
+ /// , сумма векторов
+ public static Vector operator +(Vector v, Vector u)
+ {
+ return v.Add(u);
+ }
+
+ ///
+ /// Вычитает один из другого и возвращает новый
+ ///
+ /// , левое слагаемое
+ /// , правое слагаемое
+ /// , результат вычитания
+ public static Vector operator -(Vector v, Vector u)
{
- throw new NotImplementedException();
+ return new Vector(v.X - u.X, v.Y - u.Y);
+ }
+
+ ///
+ /// Возвращает , умноженный на число
+ ///
+ /// , коэффициент умножения
+ /// Исходный
+ /// , умноженный на число
+ public static Vector operator *(double k, Vector v)
+ {
+ return v.Scale(k);
+ }
+
+ ///
+ /// Возвращает , умноженный на число
+ ///
+ /// Исходный
+ /// , коэффициент умножения
+ /// , умноженный на число
+ public static Vector operator *(Vector v, double k)
+ {
+ return v.Scale(k);
+ }
+
+ ///
+ /// Возвращает , нормированный на число
+ ///
+ /// Исходный
+ /// , коэффициент нормировки
+ /// , нормированный на число
+ public static Vector operator /(Vector v, double k)
+ {
+ return v.Scale(1 / k);
+ }
+
+ ///
+ /// Возвращает неизмененный
+ ///
+ /// Исходный
+ /// Неизмененный
+ public static Vector operator +(Vector v)
+ {
+ return v;
+ }
+
+ ///
+ /// Возвращает , направленный противоположно данному
+ ///
+ /// Исходный
+ /// , направленный противоположно данному
+ public static Vector operator -(Vector v)
+ {
+ return new Vector(-v.X, -v.Y);
}
}
-
- #endregion
-
-
- #region 4. Тесты
-
- /*
- Прости еще раз, но на этом твои мучения еще не кончаются. Проблема в том, что у котика все еще лапки, поэтому очень важно
- покрыть тестами хотя бы базовые методы структуры Vector:
- SquareLength
- Add
- Scale
- DotProduct
- CrossProduct
-
- Для этого создай в этом же солюшене (если ты не в студии, то можешь и не в солюшене) проект BoringVector.Tests,
- который будет содержать класс с набором тестов. Используй Xunit (в принципе можешь воспользоваться и другим фреймворком для тестирования).
-
- Особо не заморачивайся с тем, чтобы оттестировать все возможные специальные случаи - в данном задании важно, чтобы
- ты просто разобрался(-ась), как писать автотесты и как их запускать. Это задание НЕ на то, как писать хорошие тесты.
-
- Примечание: структура Vector описана как internal структура, поэтому по умолчанию сборке BoringVector.Tests она не видна.
- Чтобы она была видна, существует специальная директива компилятору:
- [assembly: InternalsVisibleTo("XXX")]
- , где XXX - название проекта, которому ты хочешь сделать видимыми свои internal'ы.
-
- Можешь посмотреть, в задании [01-primitive-types] эта директива есть в файле Program.cs проекта Numbers.
-
- Итак, создай проект с тестами и добейся того, чтобы базовые методы структуры Vector их проходили.
- */
-
- #endregion
-
-
- /*
- На этом все. Время делать пулл реквест и наслаждаться заслуженным отдыхом :)
- */
-}
+}
\ No newline at end of file
diff --git a/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector/VectorExtensions.cs b/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector/VectorExtensions.cs
index 525be40f..f5b11f3d 100644
--- a/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector/VectorExtensions.cs
+++ b/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector/VectorExtensions.cs
@@ -1,10 +1,91 @@
-namespace BoringVector
+using System;
+
+namespace BoringVector
{
- /*
- Здесь тебе нужно написать класс с методами-расширениями структуры Vector:
- - IsZero: проверяет, является ли вектор нулевым, т.е. его координаты близки к нулю (в эпсилон окрестности). За эпсилон здесь и далее берем 1e-6.
- - Normalize: нормализует вектор
- - GetAngleBetween: возвращает угол между двумя векторами в радианах. Примечание: нулевой вектор сонаправлен любому другому.
- - GetRelation: возвращает значение перечесления VectorRelation(General, Parallel, Orthogonal) - отношение между двумя векторами("общий случай", параллельны, перпендикулярны). Перечисление задавать тоже тебе)
- */
-}
+ ///
+ /// Отношение между двумя векторами (общий случай, параллельны, перпендикулярны)
+ ///
+ enum VectorRelation { General, Parallel, Orthogonal };
+
+ ///
+ /// Методы-расширения структуры Vector
+ ///
+ static class VectorExtensions
+ {
+ ///
+ /// Проверяет, является ли вектор нулевым c погрешностью по длине в 1e-6.
+ ///
+ /// Объект
+ /// , является ли вектор нулевым
+ public static bool IsZero(this Vector v)
+ {
+ const double eps = 1e-6;
+ return Math.Sqrt(v.SquareLength()) < eps;
+ }
+
+ ///
+ /// Возвращает , отнормированный на его длину
+ ///
+ ///
+ /// , отнормированный на его длину
+ public static Vector Normalize(this Vector v)
+ {
+ if (v.IsZero())
+ {
+ return v;
+ }
+
+ return v / Math.Sqrt(v.SquareLength());
+ }
+
+ ///
+ /// Возвращает , угол между двумя векторами в радианах
+ ///
+ /// Первый
+ /// Второй
+ /// , угол между двумя векторами в радианах
+ public static double GetAngleBetween(this Vector v, Vector u)
+ {
+ if (v.IsZero() || u.IsZero())
+ {
+ return 0;
+ }
+
+ var cos = v.DotProduct(u) / Math.Sqrt(v.SquareLength() * u.SquareLength());
+ if (cos < -1)
+ {
+ return Math.PI;
+ }
+
+ if (cos > 1)
+ {
+ return 0;
+ }
+
+ return Math.Acos(cos);
+ }
+
+ ///
+ /// Возвращает отношение (VectorRelation) между двумя векторами
+ ///
+ /// Первый
+ /// Второй
+ /// Отношение (VectorRelation) между двумя векторами
+ public static VectorRelation GetRelation(this Vector v, Vector u)
+ {
+ const double eps = 1e-6;
+ var angle = v.GetAngleBetween(u);
+ if (angle < eps || Math.PI - angle < eps)
+ {
+ return VectorRelation.Parallel;
+ }
+
+ if (Math.Abs(angle - Math.PI / 2) < eps)
+ {
+ return VectorRelation.Orthogonal;
+ }
+
+ return VectorRelation.General;
+ }
+ }
+}
\ No newline at end of file
diff --git a/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub.Tests/RicksMercilessEncryptorTests.cs b/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub.Tests/RicksMercilessEncryptorTests.cs
index 434f02aa..b6083b34 100644
--- a/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub.Tests/RicksMercilessEncryptorTests.cs
+++ b/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub.Tests/RicksMercilessEncryptorTests.cs
@@ -1,10 +1,94 @@
using System;
+using System.Collections.Immutable;
using Xunit;
namespace WubbaLubbaDubDub.Tests
{
public class RicksMercilessEncryptorTests
{
+ [Theory]
+ [InlineData("Простой текст", new []{"Простой текст"})]
+ [InlineData("Текст, разделенный\nпереводами\nстроки.", new[]{"Текст, разделенный", "переводами", "строки."})]
+ public void Test_SplitToLines_ReturnsCorrectValue(string text, string[] expectedLines)
+ {
+ Assert.Equal(expectedLines, text.SplitToLines());
+ }
+ [Theory]
+ [InlineData("Простой текст", new []{"Простой", "текст"})]
+ [InlineData(" , .\r\nТекст,\t с 15: ..разными\n\n\t\t:;' символами!?\t\t \r\n", new[]{"Текст", "с", "15", "разными", "символами"})]
+ public void Test_SplitToWords_ReturnsCorrectValue(string line, string[] expectedWords)
+ {
+ Assert.Equal(expectedWords, line.SplitToWords());
+ }
+
+ [Theory]
+ [InlineData("", "")]
+ [InlineData("а", "")]
+ [InlineData("аб", "а")]
+ [InlineData("строка", "стр")]
+ [InlineData("строчка", "стр")]
+ public void Test_GetLeftHalf_ReturnsCorrectValue(string s, string expectedLeftHalf)
+ {
+ Assert.Equal(expectedLeftHalf, s.GetLeftHalf());
+ }
+
+ [Theory]
+ [InlineData("", "")]
+ [InlineData("строка", "ока")]
+ [InlineData("строчка", "очка")]
+ public void Test_GetRightHalf_ReturnsCorrectValue(string s, string expectedRightHalf)
+ {
+ Assert.Equal(expectedRightHalf, s.GetRightHalf());
+ }
+
+ [Theory]
+ [InlineData("один одиннадцать", "один", "три", "три тринадцать")]
+ [InlineData("строка как строка", "строка", "текст", "текст как текст")]
+ public void Test_Replace_ReturnsCorrectValue(string s, string old, string @new, string expected)
+ {
+ Assert.Equal(expected, RicksMercilessEncryptor.Replace(s, old, @new));
+ }
+
+ [Theory]
+ [InlineData("Слово", @"\u0421\u043B\u043E\u0432\u043E")]
+ [InlineData("français", @"\u0066\u0072\u0061\u006E\u00E7\u0061\u0069\u0073")]
+ public void Test_CharsToCodes_ReturnsCorrectValue(string chars, string expectedCodes)
+ {
+ Assert.Equal(expectedCodes, chars.CharsToCodes());
+ }
+
+ [Theory]
+ [InlineData("Слово", "оволС")]
+ [InlineData("français", "siaçnarf")]
+ public void Test_GetReversed_ReturnsCorrectValue(string value, string expectedReversed)
+ {
+ Assert.Equal(expectedReversed, value.GetReversed());
+ }
+
+ [Theory]
+ [InlineData("СлОвЕчКо", "сЛоВеЧкО")]
+ [InlineData("français", "FRANÇAIS")]
+ [InlineData("2021 год", "2021 ГОД")]
+ public void Test_InverseCase_ReturnsCorrectValue(string value, string expectedInversed)
+ {
+ Assert.Equal(expectedInversed, value.InverseCase());
+ }
+
+ [Theory]
+ [InlineData("абвгддд", "бвгдеее")]
+ [InlineData("français", "gsboèbjt")]
+ public void Test_ShiftInc_ReturnsCorrectValue(string value, string expectedShifted)
+ {
+ Assert.Equal(expectedShifted, value.ShiftInc());
+ }
+
+ [Theory]
+ [InlineData("траляля 0001:0000 /*12 1234:56AF*/", new []{65536L})]
+ [InlineData("//1234:56AF\n 0000:0012 //AAAA:AAAA\n /* 2314:ABCD*/", new []{18L})]
+ public void Test_GetUsedObjects_ReturnsCorrectValue(string value, long[] expectedObjects)
+ {
+ Assert.Equal(ImmutableArray.Create(expectedObjects), value.GetUsedObjects());
+ }
}
-}
+}
\ No newline at end of file
diff --git a/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub/RicksMercilessEncryptor.cs b/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub/RicksMercilessEncryptor.cs
index 1063065b..b742e22c 100644
--- a/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub/RicksMercilessEncryptor.cs
+++ b/course-2021-1/exercises/04-wubba-lubba-dub-dub/WubbaLubbaDubDub/WubbaLubbaDubDub/RicksMercilessEncryptor.cs
@@ -1,6 +1,7 @@
using System;
-using System.Collections.Generic;
using System.Collections.Immutable;
+using System.Linq;
+using System.Text.RegularExpressions;
namespace WubbaLubbaDubDub
{
@@ -11,8 +12,7 @@ public static class RicksMercilessEncryptor
///
public static string[] SplitToLines(this string text)
{
- // У строки есть специальный метод. Давай здесь без регулярок
- throw new NotImplementedException();
+ return text.Split('\n');
}
///
@@ -20,8 +20,8 @@ public static string[] SplitToLines(this string text)
///
public static string[] SplitToWords(this string line)
{
- // А вот здесь поиграйся с регулярками.
- throw new NotImplementedException();
+ var words = Regex.Split(line, "\\W+");
+ return Array.FindAll(words, word => word.Length > 0);
}
///
@@ -30,8 +30,7 @@ public static string[] SplitToWords(this string line)
///
public static string GetLeftHalf(this string s)
{
- // у строки есть метод получения подстроки
- throw new NotImplementedException();
+ return s.Substring(0, s.Length / 2);
}
///
@@ -40,7 +39,7 @@ public static string GetLeftHalf(this string s)
///
public static string GetRightHalf(this string s)
{
- throw new NotImplementedException();
+ return s.Substring(s.Length / 2);
}
///
@@ -48,8 +47,7 @@ public static string GetRightHalf(this string s)
///
public static string Replace(this string s, string old, string @new)
{
- // и такой метод у строки, очевидно, тоже есть
- throw new NotImplementedException();
+ return s.Replace(old, @new);
}
///
@@ -58,14 +56,12 @@ public static string Replace(this string s, string old, string @new)
///
public static string CharsToCodes(this string s)
{
- /*
- Может быть удобным здесь же сначала написать локальную функцию
- которая содержит логику для преобразования одного символа,
- а затем использовать её для посимвольного преобразования всей строки.
- FYI: локальную функцию можно объявлять даже после строки с return.
- То же самое можно сделать и для всех оставшихся методов.
- */
- throw new NotImplementedException();
+ return string.Concat(s.Select(CharToCode));
+
+ string CharToCode(char c)
+ {
+ return string.Concat("\\u", Convert.ToInt32(c).ToString("X4"));
+ }
}
///
@@ -73,11 +69,7 @@ public static string CharsToCodes(this string s)
///
public static string GetReversed(this string s)
{
- /*
- Собрать строку из последовательности строк можно несколькими способами.
- Один из низ - статический метод Concat. Но ты можешь выбрать любой.
- */
- throw new NotImplementedException();
+ return string.Concat(s.ToCharArray().Reverse());
}
///
@@ -85,12 +77,12 @@ public static string GetReversed(this string s)
///
public static string InverseCase(this string s)
{
- /*
- Здесь тебе помогут статические методы типа char.
- На минуту задержись здесь и посмотри, какие еще есть статические методы у char.
- Например, он содержит методы-предикаты для определения категории Юникода символа, что очень удобно.
- */
- throw new NotImplementedException();
+ return string.Concat(s.Select(InverseCase));
+
+ char InverseCase(char c)
+ {
+ return char.IsLower(c) ? char.ToUpper(c) : char.ToLower(c);
+ }
}
///
@@ -99,12 +91,13 @@ public static string InverseCase(this string s)
///
public static string ShiftInc(this string s)
{
- throw new NotImplementedException();
+ return string.Concat(s.Select(ShiftInc));
+ char ShiftInc(char c)
+ {
+ return Convert.ToChar(Convert.ToInt32(c) + 1);
+ }
}
-
- #region Чуть посложнее
-
///
/// Возвращает список уникальных идентификаторов объектов, используемых в тексте .
/// Идентификаторы объектов имеют длину 8байт и представлены в тексте в виде ¶X:Y¶, где X - старшие 4 байта, а Y - младшие 4 байта.
@@ -113,13 +106,14 @@ public static string ShiftInc(this string s)
///
public static IImmutableList GetUsedObjects(this string text)
{
- /*
- Задача на поиграться с регулярками - вся сложность в том, чтобы аккуратно игнорировать комментарии.
- Экспериментировать онлайн можно, например, здесь: http://regexstorm.net/tester и https://regexr.com/
- */
- throw new NotImplementedException();
- }
+ var commentRegex = new Regex(@"((\/\*)((?!\*\/)(.|\n))*(\*\/))|(\/\/.*\n)", RegexOptions.Multiline);
+ var cleanText = commentRegex.Replace(text, "");
+ var idRegex = new Regex(@"[0-9A-F]{4}:[0-9A-F]{4}", RegexOptions.Multiline);
- #endregion
+ return idRegex
+ .Matches(cleanText)
+ .Select(id => Convert.ToInt64(id.Value.Substring(5), 16) + (Convert.ToInt64(id.Value.Substring(0, 4), 16) << 16))
+ .ToImmutableList();
+ }
}
-}
+}
\ No newline at end of file
diff --git a/course-2021-1/exercises/05-drunk-fibonacci/DrunkFibonacci/DrunkFibonacci/DrunkFibonacci.cs b/course-2021-1/exercises/05-drunk-fibonacci/DrunkFibonacci/DrunkFibonacci/DrunkFibonacci.cs
index ac217f0d..405104e4 100644
--- a/course-2021-1/exercises/05-drunk-fibonacci/DrunkFibonacci/DrunkFibonacci/DrunkFibonacci.cs
+++ b/course-2021-1/exercises/05-drunk-fibonacci/DrunkFibonacci/DrunkFibonacci/DrunkFibonacci.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Linq;
namespace DrunkFibonacci
{
@@ -11,8 +12,7 @@ internal static class DrunkFibonacci
/// Длина массива
public static int[] CreateIntArray(int len)
{
- // на создание массивов заданной длины
- throw new NotImplementedException();
+ return new int[len];
}
///
@@ -23,8 +23,10 @@ public static int[] CreateIntArray(int len)
/// Шаг прогрессии.
public static void FillIntArray(int[] arr, int seed, int step)
{
- // на задание значений массива
- throw new NotImplementedException();
+ for (var i = 0; i < arr.Length; ++i, seed += step)
+ {
+ arr[i] = seed;
+ }
}
///
@@ -33,8 +35,7 @@ public static void FillIntArray(int[] arr, int seed, int step)
///
public static int[] GetFirstFiveFibonacci()
{
- // на создание массива с инициализацией
- throw new NotImplementedException();
+ return new[] {0, 1, 1, 2, 3};
}
///
@@ -42,14 +43,12 @@ public static int[] GetFirstFiveFibonacci()
///
public static IEnumerable GetDeterministicRandomSequence()
{
- /*
- Воспользуйся классом Random.
- Для того, чтобы данный объект генерировал одну и ту же последовательность,
- его следует инициализировать одной и той же константой (параметр конструктора seed).
-
- Задача на ленивую генерацию последовательностей.
- */
- throw new NotImplementedException();
+ const int seed = 42;
+ var rnd = new Random(seed);
+ while (true)
+ {
+ yield return rnd.Next();
+ }
}
///
@@ -57,17 +56,42 @@ public static IEnumerable GetDeterministicRandomSequence()
///
public static IEnumerable GetDrunkFibonacci()
{
- /*
- Первые два значения: 1 и 1.
- Каждое 6е число забывает озвучить (но учитывает при подсчете следующего).
- Каждое 6е, начиная с 4го, вставляет очередную "шутку за 300": число 300.
- У получившегося числа с некоторой вероятностью зануляет биты,
- соответствующие числу 42 (т.е. те биты, которые в бинарном представлении числа 42 равны единице).
- Вероятность считается так. На каждом i-ом этапе вычисления нового значения X последовательности берешь так же число Y
- из последовательности GetDeterministicRandomSequence и проверяешь, есть ли у числа Y единичные биты числа 42.
- При вычислении сложения переполнение типа разрешено и всячески поощряется.
- */
- throw new NotImplementedException();
+ bool IsSilent(int position) => position % 6 == 0;
+ bool AddThreeHundred(int position) => IsSilent(position) && position > 6 * 4;
+
+ var prevValue = 1;
+ var currValue = 1;
+ var currPos = 2;
+
+ var randomEnumerator = GetDeterministicRandomSequence().GetEnumerator();
+ randomEnumerator.MoveNext();
+ randomEnumerator.MoveNext();
+
+ while (true)
+ {
+ ++currPos;
+ randomEnumerator.MoveNext();
+ prevValue += currValue;
+ (prevValue, currValue) = (currValue, prevValue);
+
+ if (AddThreeHundred(currPos))
+ {
+ ++currPos;
+ randomEnumerator.MoveNext();
+ prevValue = currValue;
+ currValue = 300;
+ }
+
+ if ((randomEnumerator.Current & 42) != 0)
+ {
+ currValue &= ~42;
+ }
+
+ if (!IsSilent(currPos))
+ {
+ yield return currValue;
+ }
+ }
}
///
@@ -77,8 +101,7 @@ public static IEnumerable GetDrunkFibonacci()
/// Длина отрезка.
public static int GetMaxOnRange(int from, int cnt)
{
- // научишься пропускать и брать фиксированную часть последовательности, агрегировать. Максимум есть среди готовых функций агрегации.
- throw new NotImplementedException();
+ return GetDrunkFibonacci().Skip(from - 1).Take(cnt).Max();
}
///
@@ -87,8 +110,7 @@ public static int GetMaxOnRange(int from, int cnt)
/// Индекс начала поиска отрезка. Нумерация с единицы.
public static List GetNextNegativeRange(int from = 1)
{
- // научишься пропускать и брать по условию, превращать в список (см. ToList).
- throw new NotImplementedException();
+ return GetDrunkFibonacci().Skip(from - 1).SkipWhile(val => val >= 0).TakeWhile(val => val < 0).ToList();
}
///
@@ -96,8 +118,7 @@ public static List GetNextNegativeRange(int from = 1)
///
public static IEnumerable GetXoredWithLaggedItself()
{
- // узнаешь о существовании функции Zip.
- throw new NotImplementedException();
+ return GetDrunkFibonacci().Zip(GetDrunkFibonacci().Skip(42), (left, right) => left ^ right);
}
///
@@ -105,8 +126,19 @@ public static IEnumerable GetXoredWithLaggedItself()
///
public static IEnumerable GetInChunks()
{
- // ни чему особо не научишься, просто интересная задачка :)
- throw new NotImplementedException();
+ var fibEnumerator = GetDeterministicRandomSequence().GetEnumerator();
+ while (true)
+ {
+ const int len = 16;
+ var chunk = new int[len];
+ for (var i = 0; i < len; ++i)
+ {
+ chunk[i] = fibEnumerator.Current;
+ fibEnumerator.MoveNext();
+ }
+
+ yield return chunk;
+ }
}
///
@@ -115,14 +147,7 @@ public static IEnumerable GetInChunks()
///
public static IEnumerable FlattenChunkedSequence()
{
- /*
- Узнаешь о встроенных функциях сортировки и функции SelectMany,
- которая сглаживает (flatten) последовательность последовательностей в просто последовательность.
-
- Вообще говоря, SelectMany умеет много чего и мегаполезна.
- Она в какой-то степени эквивалентна оператору `bind` над монадами (в данном случае над монадами последовательностей).
- */
- throw new NotImplementedException();
+ return GetInChunks().SelectMany(chunk => chunk.OrderBy(Math.Abs).Take(3));
}
///
@@ -135,28 +160,16 @@ public static IEnumerable FlattenChunkedSequence()
///
public static Dictionary GetGroupSizes()
{
- /*
- Хочется увидеть решение через группировку и агрегацию. Для группировки существуют два метода-расширения GroupBy и ToLookup.
- Они внешне немного похожи, но на самом деле очень сильно различаются семантически.
-
- Первый - ленивый (как Take, Where, Select и куча других) и лишь декларирует группировку, т.е. конструирует
- новый объект с информацией о том, как производить группировку (сама итерация по исходной последовательности
- при вызове метода GroupBy не производится). Это бывает удобно, например, при описании запросов к БД, используя ORM'ки -
- GroupBy будет правильно истолковано конструктором запросов и группировка будет произведена на стороне БД, а не на стороне кода,
- что и быстрее, и требует передачи меньшего кол-ва данных.
- Если у объекта, полученного вызовом .GroupBy дважды вызвать методы, инициирующие итерацию, то она будет произведена дважды.
-
- Второй - не ленивый и производит непосредственно саму группировку. Можно трактовать это как "промежуточное кэширование" группировки для быстрого
- [и возможно повторного] доступа к группам. Т.е. ты один раз произвел группировку, дальше пользуешься уже ей отдельно от оригинальной последовательности -
- это не потребует повторных итераций по ней.
- По сути ILookup аналогичен IDictionary> - разница лишь в том, что
- обращение к несуществующему ключу лукапа будет выдавать пустую последовательность, в то время как словарь сгенерирует исключение.
-
- Конкретно в этом задании более к месту будет выглядеть использование GroupBy. Но можешь ради интереса воспользоваться и ToLookup.
-
- Итого научишься группировать и создавать на их основе словарь (см. ToDictionary).
- */
- throw new NotImplementedException();
+ return GetDrunkFibonacci()
+ .Take(10000)
+ .GroupBy(
+ val => val % 8,
+ (mod, vals) => new
+ {
+ mod,
+ count = vals.Count()
+ })
+ .ToDictionary(item => item.mod, item => item.count);
}
}
-}
+}
\ No newline at end of file