diff --git a/exercises/practice/simple-linked-list/.docs/instructions.append.md b/exercises/practice/simple-linked-list/.docs/instructions.append.md index 457bb58d0f..e095289d61 100644 --- a/exercises/practice/simple-linked-list/.docs/instructions.append.md +++ b/exercises/practice/simple-linked-list/.docs/instructions.append.md @@ -1,4 +1,10 @@ -# Hints +# Instruction append -This exercise requires you to create a linked list data structure which can be iterated. This requires you to implement the IEnumerable\ interface. -For more information, see [this page](https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.ienumerable-1). +This exercise requires you to create a linked list data structure which can be iterated. + +1. Implement the `Count` property - it should not be possible to change its value from the outside +2. Implement the `Push(T value)` method that adds a value to the list at its head. +3. Implement the `Pop()` method which removes and returns a value from the head. +4. Add a constructor to allow initialisation with a single value, or with an interable +5. Implement the `IEnumerable` interface. For more information, see [this page](https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.ienumerable-1). +6. Ensure `Reverse()` method is available. diff --git a/exercises/practice/simple-linked-list/.meta/Example.cs b/exercises/practice/simple-linked-list/.meta/Example.cs index c7466ceeb3..ba5e08b6b1 100644 --- a/exercises/practice/simple-linked-list/.meta/Example.cs +++ b/exercises/practice/simple-linked-list/.meta/Example.cs @@ -1,63 +1,53 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Linq; public class SimpleLinkedList : IEnumerable { - public SimpleLinkedList(T value) : - this(new[] { value }) - { + private class Node { + public T Value { get; set; } + public Node Next { get; set; } } + + private Node head; - public SimpleLinkedList(IEnumerable values) - { - var array = values.ToArray(); - - if (array.Length == 0) - { - throw new ArgumentException("Cannot create tree from empty list"); - } - - Value = array[0]; - Next = null; + public SimpleLinkedList() { } - foreach (var value in array.Skip(1)) - { - Add(value); + public SimpleLinkedList(params T[] values) + { + foreach(var value in values) { + Push(value); } } - public T Value { get; } - - public SimpleLinkedList Next { get; private set; } - - public SimpleLinkedList Add(T value) + public int Count { get; private set; } = 0; + + public void Push(T value) { - var last = this; + var node = new Node { Value = value, Next = this.head }; + this.head = node; + this.Count++; + } - while (last.Next != null) - { - last = last.Next; + public T Pop() + { + if (this.head == null) { + throw new InvalidOperationException("List is empty!"); } - - last.Next = new SimpleLinkedList(value); - - return this; + var value = head.Value; + head = head.Next; + this.Count--; + return value; } public IEnumerator GetEnumerator() { - yield return Value; - - foreach (var next in Next?.AsEnumerable() ?? Enumerable.Empty()) - { - yield return next; + var current = this.head; + while(current != null) { + yield return current.Value; + current = current.Next; } } - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } \ No newline at end of file diff --git a/exercises/practice/simple-linked-list/.meta/config.json b/exercises/practice/simple-linked-list/.meta/config.json index 4a0d1bc2be..a3e1e533c7 100644 --- a/exercises/practice/simple-linked-list/.meta/config.json +++ b/exercises/practice/simple-linked-list/.meta/config.json @@ -6,7 +6,8 @@ "bressain", "j2jensen", "robkeim", - "wolf99" + "wolf99", + "michalporeba" ], "files": { "solution": [ diff --git a/exercises/practice/simple-linked-list/SimpleLinkedList.cs b/exercises/practice/simple-linked-list/SimpleLinkedList.cs index bb6682f740..457d8e4b77 100644 --- a/exercises/practice/simple-linked-list/SimpleLinkedList.cs +++ b/exercises/practice/simple-linked-list/SimpleLinkedList.cs @@ -1,47 +1,15 @@ using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -public class SimpleLinkedList : IEnumerable +public class SimpleLinkedList { - public SimpleLinkedList(T value) + public int Count => throw new NotImplementedException("You need to implement this function."); + + public void Push(T value) { throw new NotImplementedException("You need to implement this function."); } - public SimpleLinkedList(IEnumerable values) - { - throw new NotImplementedException("You need to implement this function."); - } - - public T Value - { - get - { - throw new NotImplementedException("You need to implement this function."); - } - } - - public SimpleLinkedList Next - { - get - { - throw new NotImplementedException("You need to implement this function."); - } - } - - public SimpleLinkedList Add(T value) - { - throw new NotImplementedException("You need to implement this function."); - } - - public IEnumerator GetEnumerator() - { - throw new NotImplementedException("You need to implement this function."); - } - - IEnumerator IEnumerable.GetEnumerator() + public T Pop() { throw new NotImplementedException("You need to implement this function."); } diff --git a/exercises/practice/simple-linked-list/SimpleLinkedListTests.cs b/exercises/practice/simple-linked-list/SimpleLinkedListTests.cs index 35a89822d2..3d78d198dc 100644 --- a/exercises/practice/simple-linked-list/SimpleLinkedListTests.cs +++ b/exercises/practice/simple-linked-list/SimpleLinkedListTests.cs @@ -1,83 +1,117 @@ +using System; using System.Linq; +using System.Collections.Generic; using Xunit; public class SimpleLinkedListTests { - [Fact] - public void Single_item_list_value() + [Fact] + public void Empty_list_has_no_elements() { - var list = new SimpleLinkedList(1); - Assert.Equal(1, list.Value); + var list = new SimpleLinkedList(); + Assert.Equal(0, list.Count); } [Fact(Skip = "Remove this Skip property to run this test")] - public void Single_item_list_has_no_next_item() + public void Count_cannot_be_changed_from_the_outside() { - var list = new SimpleLinkedList(1); - Assert.Null(list.Next); + var count = typeof(SimpleLinkedList<>).GetProperty("Count"); + Assert.True(count?.GetGetMethod().IsPublic); + Assert.False(count?.GetSetMethod(true).IsPublic); } [Fact(Skip = "Remove this Skip property to run this test")] - public void Two_item_list_first_value() + public void Pushing_elements_to_the_list_increases_the_count() { - var list = new SimpleLinkedList(2).Add(1); - Assert.Equal(2, list.Value); + var list = new SimpleLinkedList(); + list.Push(0); + Assert.Equal(1, list.Count); + list.Push(0); + Assert.Equal(2, list.Count); } [Fact(Skip = "Remove this Skip property to run this test")] - public void Two_item_list_second_value() + public void Popping_elements_from_the_list_decreases_the_count() { - var list = new SimpleLinkedList(2).Add(1); - Assert.Equal(1, list.Next.Value); + var list = new SimpleLinkedList(); + list.Push(0); + list.Push(0); + Assert.Equal(2, list.Count); + list.Pop(); + Assert.Equal(1, list.Count); } [Fact(Skip = "Remove this Skip property to run this test")] - public void Two_item_list_second_item_has_no_next() + public void Elements_pop_back_in_lifo_order() { - var list = new SimpleLinkedList(2).Add(1); - Assert.Null(list.Next.Next); + var list = new SimpleLinkedList(); + list.Push(3); + list.Push(5); + Assert.Equal(5, list.Pop()); + list.Push(7); + Assert.Equal(7, list.Pop()); + Assert.Equal(3, list.Pop()); + } + + private static SimpleLinkedList CreateSimpleLinkedList(int value) + { + var type = typeof(SimpleLinkedList<>).MakeGenericType(typeof(int)); + var constructor = type.GetConstructor(new Type[] { typeof(int) }); + return (SimpleLinkedList)constructor?.Invoke(new object[]{ value }) + ?? CreateSimpleLinkedList(new int[] { value }); + } + + private static SimpleLinkedList CreateSimpleLinkedList(params int[] values) + { + var type = typeof(SimpleLinkedList<>).MakeGenericType(typeof(int)); + var constructor = type.GetConstructor(new Type[]{typeof(int[])}); + return (SimpleLinkedList)constructor.Invoke(new object[]{ values }); } [Fact(Skip = "Remove this Skip property to run this test")] - public void Implements_enumerable() + public void Single_value_initialisation() { - var values = new SimpleLinkedList(2).Add(1); - Assert.Equal(new[] { 2, 1 }, values); + var list = CreateSimpleLinkedList(7); + Assert.Equal(1, list.Count); + Assert.Equal(7, list.Pop()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Multi_value_initialisation() + { + var list = CreateSimpleLinkedList(2, 1, 3); + Assert.Equal(3, list.Pop()); + Assert.Equal(1, list.Pop()); + Assert.Equal(2, list.Pop()); } [Fact(Skip = "Remove this Skip property to run this test")] public void From_enumerable() { - var list = new SimpleLinkedList(new[] { 11, 7, 5, 3, 2 }); - Assert.Equal(11, list.Value); - Assert.Equal(7, list.Next.Value); - Assert.Equal(5, list.Next.Next.Value); - Assert.Equal(3, list.Next.Next.Next.Value); - Assert.Equal(2, list.Next.Next.Next.Next.Value); + var list = CreateSimpleLinkedList(new[] { 11, 7, 5, 3, 2 }); + Assert.Equal(2, list.Pop()); + Assert.Equal(3, list.Pop()); + Assert.Equal(5, list.Pop()); + Assert.Equal(7, list.Pop()); + Assert.Equal(11, list.Pop()); } - [Theory(Skip = "Remove this Skip property to run this test")] - [InlineData(1)] - [InlineData(2)] - [InlineData(10)] - [InlineData(100)] - public void Reverse(int length) + [Fact(Skip = "Remove this Skip property to run this test")] + public void Reverse_enumerable() { - var values = Enumerable.Range(1, length).ToArray(); - var list = new SimpleLinkedList(values); - var reversed = list.Reverse(); - Assert.Equal(values.Reverse(), reversed); + var values = Enumerable.Range(1, 5).ToArray(); + var list = CreateSimpleLinkedList(values); + var enumerable = Assert.IsAssignableFrom>(list); + var reversed = enumerable.Reverse(); + Assert.Equal(values, reversed); } - [Theory(Skip = "Remove this Skip property to run this test")] - [InlineData(1)] - [InlineData(2)] - [InlineData(10)] - [InlineData(100)] - public void Roundtrip(int length) + [Fact(Skip = "Remove this Skip property to run this test")] + public void Roundtrip() { - var values = Enumerable.Range(1, length); - var listValues = new SimpleLinkedList(values); - Assert.Equal(values, listValues); + var values = Enumerable.Range(1, 7); + var list = CreateSimpleLinkedList(values.ToArray()); + var enumerable = Assert.IsAssignableFrom>(list); + Assert.Equal(values.Reverse(), enumerable); } } \ No newline at end of file