Skip to content

Instantly share code, notes, and snippets.

@pkuderov
Created January 31, 2018 11:40
Show Gist options
  • Save pkuderov/b8d7d9b464f23b876f5441ef4276c979 to your computer and use it in GitHub Desktop.
Save pkuderov/b8d7d9b464f23b876f5441ef4276c979 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Linq;
namespace DrunkFibonacci
{
internal static class DrunkFibonacci
{
/// <summary>
/// Создает пустой массив заданной длины.
/// </summary>
/// <param name="len">Длина массива</param>
public static int[] CreateIntArray(int len)
{
// на создание массивов заданной длины
if (len <= 0)
{
throw new ArgumentException("Invalid array length");
}
return new int[len];
}
/// <summary>
/// Заполняет заданный массив значениями арифметической прогрессии на основе <see cref="seed"/> и <see cref="step"/>.
/// </summary>
/// <param name="arr">Заданный массив.</param>
/// <param name="seed">База прогрессии.</param>
/// <param name="step">Шаг прогрессии.</param>
public static void FillIntArray(int[] arr, int seed, int step)
{
// на задание значений массива
if (arr == null)
{
return;
}
for (var i = 0; i < arr.Length; ++i)
{
arr[i] = seed + i * step;
}
}
/// <summary>
/// Возвращает массив из первых пяти значений последовательности Фибоначчи.
/// </summary>
/// <returns></returns>
public static int[] GetFirstFiveFibonacci()
{
// на создание массива с инициализацией
return new[] { 1, 1, 2, 3, 5 };
}
/// <summary>
/// Возвращает последовательность случайных чисел, которая сгенерирована на основе некоторого постоянного определителя.
/// </summary>
public static IEnumerable<int> GetDeterministicRandomSequence()
{
/*
Воспользуйся классом Random.
Для того, чтобы данный объект генерировал одну и ту же последовательность,
его следует инициализировать одной и той же константой (параметр конструктора seed).
Задача на ленивую генерацию последовательностей.
*/
var randomGenerator = new Random(22);
while (true)
{
yield return randomGenerator.Next();
}
}
/// <summary>
/// Возвращает последовательность Фибоначчи, которая слегка перебрала и теперь путается, что-то забывает или по десятому разу рассказывает одни и те же шутки :)
/// </summary>
public static IEnumerable<int> GetDrunkFibonacci()
{
/*
Первые два значения: 1 и 1.
Каждое 6е число забывает озвучить (но учитывает при подсчете следующего).
Каждое 6е, начиная с 4го, вставляет очередную "шутку за 300": число 300.
У получившегося числа с некоторой вероятностью зануляет биты,
соответствующие числу 42 (т.е. те биты, которые в бинарном представлении числа 42 равны единице).
Вероятность считается так. На каждом i-ом этапе вычисления нового значения X последовательности берешь так же число Y
из последовательности GetDeterministicRandomSequence и проверяешь, есть ли у числа Y единичные биты числа 42.
При вычислении сложения переполнение типа разрешено и всячески поощряется.
*/
var output = 0;
var previous = 1;
var current = 1;
var elementCount = 1;
foreach (var element in GetDeterministicRandomSequence())
{
if (elementCount <= 2)
{
output = 1;
}
if ((element & 42) == 42)
{
output &= ~42;
}
output = unchecked(current + previous);
if (elementCount % 6 == 4) {output = 300;}
var oldCurrent = current;
current = unchecked(current + previous);
previous = oldCurrent;
++elementCount;
if (elementCount % 6 != 0)
{
yield return output;
}
}
}
/// <summary>
/// Возвращает максимальное число на отрезке последовательности DrunkFibonacci.
/// </summary>
/// <param name="from">Индекс начала отрезка. Нумерация с единицы.</param>
/// <param name="cnt">Длина отрезка.</param>
public static int GetMaxOnRange(int from, int cnt)
{
// научишься пропускать и брать фиксированную часть последовательности, агрегировать. Максимум есть среди готовых функций агрегации.
return GetDrunkFibonacci()
.Skip(from)
.Take(cnt)
.Max();
}
/// <summary>
/// Возвращает следующий отрезок из отрицательных значений последовательности DrunkFibonacci в виде списка, начиная поиск с индекса <see cref="from"/>.
/// </summary>
/// <param name="from">Индекс начала поиска отрезка. Нумерация с единицы.</param>
public static List<int> GetNextNegativeRange(int from = 1)
{
// научишься пропускать и брать по условию, превращать в список (см. ToList).
return GetDrunkFibonacci()
.Skip(from)
.SkipWhile(x => x >= 0)
.TakeWhile(x => x < 0).ToList();
}
/// <summary>
/// Возвращает последовательность чисел вида F(i) = DrunkFibonacci(i) XOR DrunkFibonacci(i + 42)
/// </summary>
public static IEnumerable<int> GetXoredWithLaggedItself()
{
// узнаешь о существовании функции Zip.
return GetDrunkFibonacci()
.Zip(GetDrunkFibonacci().Skip(42), (x, y) => x ^ y);
}
/// <summary>
/// Возвращает последовательность DrunkFibonacci пачками по 16 значений.
/// </summary>
public static IEnumerable<int[]> GetInChunks()
{
// ни чему особо не научишься, просто интересная задачка :)
const int chunkSize = 16;
var chunk = new int[chunkSize];
var counter = 0;
foreach (var element in GetDrunkFibonacci())
{
chunk[counter] = element;
++counter;
if (counter != chunkSize) continue;
yield return chunk;
counter = 0;
chunk = new int[chunkSize];
}
}
/// <summary>
/// Возвращает выравненную последовательность GetInChunks, где из каждой пачки берется только 3 самых маленьких по модулю значения.
/// </summary>
/// <returns></returns>
public static IEnumerable<int> FlattenChunkedSequence()
{
/*
Узнаешь о встроенных функциях сортировки и функции SelectMany,
которая сглаживает (flatten) последовательность последовательностей в просто последовательность.
Вообще говоря, SelectMany умеет много чего и мегаполезна.
Она в какой-то степени эквивалентна оператору `bind` над монадами (в данном случае над монадами последовательностей).
*/
return GetInChunks()
.SelectMany(values => values.OrderBy(x => x)
.Take(3));
}
/// <summary>
/// Возвращает словарь пар { класс вычета по модулю 8; число значений в классе среди первых 10000 элементов последовательности DrunkFibonacci }.
/// Учитываются только непустые классы.
/// </summary>
/// <remarks>
/// Класс вычетов - мн-во значений, имеющих одинаковый остаток от деления на нек-е число (в данном случае 8).
/// В общем на выходе словарь пар, где ключ - остаток от деления на 8, а значение - кол-во элементов с таким остатком среди первых 10000 элементов посл-ти.
/// </remarks>
public static Dictionary<int, int> GetGroupSizes()
{
/*
Хочется увидеть решение через группировку и агрегацию. Для группировки существуют два метода-расширения GroupBy и ToLookup.
Они внешне немного похожи, но на самом деле очень сильно различаются семантически.
Первый - ленивый (как Take, Where, Select и куча других) и лишь декларирует группировку, т.е. конструирует
новый объект с информацией о том, как производить группировку (сама итерация по исходной последовательности
при вызове метода GroupBy не производится). Это бывает удобно, например, при описании запросов к БД, используя ORM'ки -
GroupBy будет правильно истолковано конструктором запросов и группировка будет произведена на стороне БД, а не на стороне кода,
что и быстрее, и требует передачи меньшего кол-ва данных.
Если у объекта, полученного вызовом .GroupBy дважды вызвать методы, инициирующие итерацию, то она будет произведена дважды.
Второй - не ленивый и производит непосредственно саму группировку. Можно трактовать это как "промежуточное кэширование" группировки для быстрого
[и возможно повторного] доступа к группам. Т.е. ты один раз произвел группировку, дальше пользуешься уже ей отдельно от оригинальной последовательности -
это не потребует повторных итераций по ней.
По сути ILookup<TKey, TVal> аналогичен IDictionary<TKey, IEnumerable<TVal>> - разница лишь в том, что
обращение к несуществующему ключу лукапа будет выдавать пустую последовательность, в то время как словарь сгенерирует исключение.
Конкретно в этом задании более к месту будет выглядеть использование GroupBy. Но можешь ради интереса воспользоваться и ToLookup.
Итого научишься группировать и создавать на их основе словарь (см. ToDictionary).
*/
return GetDrunkFibonacci()
.Take(10000)
.GroupBy(i => i % 8)
.ToDictionary(x => x.Key, x => x.Distinct().Count());
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment