Ходил на собеседование 23 марта 2021.
Дали задачку
Выполните письменное задание. Можно гуглить, ориентир по времени – 25 минут
Есть класс
class TreeNode
{
public IEnumerable<TreeNode> Children { get; }
}
Напишите функцию
IEnumerable<TreeNode> GetAllNodes(TreeNode node) {
// тут надо написать код
}
Эта функция должна возвращать IEnumerable<TreeNode>
, содержащий все элементы переданного в неё дерева, всех уровней вложенности.
Спрашиваю про порядок обхода, получаю ответ «на ваше усмотрение».
За отведённое время успеваю наколбасить решение, попутно размышляя о том, что Aux
– ужасное имя, что «тестик» в Main – это убого и не позволит ничего поправить на ходу, так как не будет гарантии, что ничего не сломается – всё то, за что в своё время на собеседованиях мы журили испытуемых.
Ещё проскакивает мысль, что List
повсюду плохо согласуется с IEnumerable и по красоте надо с yield
сделать, но понимаю, что за 25 минут не успею.
Показываю решение, меня спрашивают, что в нём не очень. Я мямлю что-то невразумительное про разрастание стека и рекурсивные вызовы.
Просят написать тест для дерева из примера. Пишу
var root = new TreeNode();
var childA = new TreeNode();
var childB = new TreeNode();
root.Children = new List<TreeNode>() { childA, childB };
var actual = GetAllNodes(root);
actual.ToList() == new List<TreeNode>() { root, childB, childA };
сопровождая ремаркой о том, что тут должен быть assert
Мне говорят, что такой ассёрт будет проваливаться. Я невнятно говорю, что из-за сравнения массивов, и надо использовать какой-нибудь метод, который я на память не помню, но должен же быть в nUnit подобный. Или на худой конец в FluentAssertion.
На этом разговор про эту задачу заканчивается.
Далее «домашняя работа», она же «работа над ошибками».
Первым делом добавляю тестов:
mkdir ListAllNodesTests
cd ListAllNodesTests
dotnet new xunit
dotnet add reference ../ListAllNodes/ListAllNodes.csproj
cd ..
dotnet sln add ./ListAllNodesTests/ListAllNodesTests.csproj
и сам тест. И он проходит...
То ли меня хотели сбить с толку (и это удалось), то ли собеседующий сам что-то подзабыл/напутал.
Пробую nUnit:
mkdir ListAllNodesNunitTests
cd ListAllNodesNunitTests
dotnet new -i NUnit3.DotNetNew.Template
echo ../ListAllNodes/ListAllNodes.csproj | xargs dotnet add reference
cd ..
echo ./ListAllNodesNunitTests/ListAllNodesNunitTests.csproj| xargs dotnet sln add
dotnet new -i NUnit3.DotNetNew.Template
взято из документации
Возня с xargs
вызвана тем, что у меня не получается нормально автокомплит для
add reference
– не хочет подсказывать пути к файлам проекта
(upd 2022-02-23: dotnet/sdk#9782)
nUnit также благополучно проходит, пробую задаунгрейдить версию до 2.7, снова получают успешное прохождение.
Немного размышляю и меня осеняет, что это в буквальном смысле одни и те же объекты –
GetAllNodes возвращает список тех же ссылок на те же объекты.
Гуглю DeepCloner, добавляю result.Add(last.DeepClone())
,
и тест начинает падать.
Добавляю FluentAssertions
и
treeNodes.Should().BeEquivalentTo(new[] {root, childA, childB}, options => options.WithStrictOrdering());
Тест зелёный. Меняю местами childA
и childB
– снова зелёный...
Ну, конечно же, – два листа не отличаются друг от друга!
День третий.
Цепляю библиотеку
BenchmarkDotNet с [MemoryDiagnoser]
Первый прогон показывает
BenchmarkDotNet=v0.12.0, OS=macOS 11.2.3 (20D91) [Darwin 20.3.0]
Intel Core i5-8259U CPU 2.30GHz (Coffee Lake), 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=5.0.103
[Host] : .NET Core 3.1.1 (CoreCLR 4.700.19.60701, CoreFX 4.700.19.60801), X64 RyuJIT
DefaultJob : .NET Core 3.1.1 (CoreCLR 4.700.19.60701, CoreFX 4.700.19.60801), X64 RyuJIT
Method | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
---|---|---|---|---|---|---|---|
StackyRecursiveBenchmark | 201.3 ns | 4.24 ns | 8.65 ns | 0.1044 | - | - | 328 B |
Надо повникать, что это значит. Но попозже, сейчас мысли переключаются на генерацию тестовых деревьев