From 6da8d4ad9a47ce007a8315223c75503ae7558803 Mon Sep 17 00:00:00 2001 From: kamendov-maxim Date: Sun, 24 Mar 2024 17:17:28 +0300 Subject: [PATCH] UniqueList --- UniqueList/List.Src/ElementExistsException.cs | 9 + UniqueList/List.Src/IList.cs | 11 + UniqueList/List.Src/List.cs | 214 ++++++++++++++++++ UniqueList/List.Src/List.csproj | 10 + UniqueList/List.Src/OutOfRangeException.cs | 9 + UniqueList/List.Src/Program.cs | 138 +++++++++++ UniqueList/List.Src/UniqueList.cs | 62 +++++ UniqueList/List.Tests/List.Tests.cs | 70 ++++++ UniqueList/List.Tests/List.Tests.csproj | 28 +++ UniqueList/List.Tests/UniqueList.Tests.cs | 13 ++ UniqueList/UniqueList.sln | 28 +++ 11 files changed, 592 insertions(+) create mode 100644 UniqueList/List.Src/ElementExistsException.cs create mode 100644 UniqueList/List.Src/IList.cs create mode 100644 UniqueList/List.Src/List.cs create mode 100644 UniqueList/List.Src/List.csproj create mode 100644 UniqueList/List.Src/OutOfRangeException.cs create mode 100644 UniqueList/List.Src/Program.cs create mode 100644 UniqueList/List.Src/UniqueList.cs create mode 100644 UniqueList/List.Tests/List.Tests.cs create mode 100644 UniqueList/List.Tests/List.Tests.csproj create mode 100644 UniqueList/List.Tests/UniqueList.Tests.cs create mode 100644 UniqueList/UniqueList.sln diff --git a/UniqueList/List.Src/ElementExistsException.cs b/UniqueList/List.Src/ElementExistsException.cs new file mode 100644 index 0000000..ce0d7b6 --- /dev/null +++ b/UniqueList/List.Src/ElementExistsException.cs @@ -0,0 +1,9 @@ +namespace Lists; + +public class ElementExistsException: Exception +{ + public ElementExistsException() { } + public ElementExistsException(string message) : base(message) { } + + public ElementExistsException(string message, Exception innerException) : base(message, innerException) { } +} diff --git a/UniqueList/List.Src/IList.cs b/UniqueList/List.Src/IList.cs new file mode 100644 index 0000000..2fb064e --- /dev/null +++ b/UniqueList/List.Src/IList.cs @@ -0,0 +1,11 @@ +namespace Lists; + +public interface IList +{ + void Add(int value); + void Insert(int index, int value); + int[] ToArray(); + int RemoveAt(int index); + int FindValue(int index); + int Count { get; } +} diff --git a/UniqueList/List.Src/List.cs b/UniqueList/List.Src/List.cs new file mode 100644 index 0000000..0da5a20 --- /dev/null +++ b/UniqueList/List.Src/List.cs @@ -0,0 +1,214 @@ +using System.Dynamic; +using System.Reflection.Metadata.Ecma335; +using System.Runtime.CompilerServices; +using System.Threading.Tasks.Dataflow; +using System.Xml; + +namespace Lists; + +/// +/// An implementation of linked list +/// +public class List: IList +{ + protected class ListElement + { + public ListElement? Next; + public ListElement? Previous; + public int Value; + public ListElement(int value) + { + Value = value; + + Next = null; + Previous = null; + } + } + + public List() + { + Count = 0; + } + + /// + /// Method to insert value at given index + /// + /// Where to insert value + /// Value to insert + /// Exception is thrown if index is less than 0 or + /// bigger than list.Count and it is impossible to insert value + public virtual void Insert(int index, int value) + { + if (index > Count || index < 0) + { + throw new OutOfRangeException(); + } + + var newElement = new ListElement(value); + + if (index == Count) + { + if (Count == 0) + { + head = newElement; + } + if (bottom is not null) + { + newElement.Previous = bottom; + bottom.Next = newElement; + } + bottom = newElement; + ++Count; + return; + } + + if (index == 0) + { + newElement = new ListElement(value); + head.Previous = newElement; + newElement.Next = head; + head = newElement; + ++Count; + return; + } + + var currenElement = FindNode(index); + newElement.Next = currenElement; + newElement.Previous = currenElement.Previous; + currenElement.Previous.Next = newElement; + currenElement.Previous = newElement; + ++Count; + } + + /// + /// Adds value to the end of list + /// + /// Value to add + public virtual void Add(int value) + { + var newElement = new ListElement(value); + if (Count == 0) + { + head = newElement; + bottom = newElement; + } + else if (Count == 1) + { + head.Next = newElement; + newElement.Previous = head; + } + else + { + bottom.Next = newElement; + newElement.Previous = bottom; + } + bottom = newElement; + ++Count; + } + + /// + /// Method to get an int array containing all the values from list in the same order + /// + /// Array with values + public int[] ToArray() + { + var output = new int[Count]; + var currenElement = head; + for (int i = 0; i < Count; ++i) + { + output[i] = currenElement.Value; + currenElement = currenElement.Next; + } + + return output; + } + + /// + /// Method allowing to remove value at given index + /// + /// Index of element to remove + /// Value of this element + /// Thrown if there is no element with such index in the list + public int RemoveAt(int index) + { + if (index > Count - 1 || index < 0 || Count == 0) + { + throw new OutOfRangeException(); + } + + if (index == Count - 1) + { + if (Count == 0) + { + head = null; + bottom = null; + } + else + { + bottom = bottom.Previous; + } + } + + int value; + + if (index == 0) + { + value = head.Value; + head = head.Next; + --Count; + return value; + } + + var element = FindNode(index); + value = element.Value; + element.Next.Previous = element.Previous; + element.Previous.Next = element.Next; + --Count; + return value; + } + + /// + /// Method to get a value of an element at a givent index + /// + /// Index of an element to find + /// Value of an element + /// Thrown if there is no element with such index in the list + public int FindValue(int index) + { + if (index > Count - 1 || index < 0) + { + throw new OutOfRangeException("Index is out of range"); + } + + var element = FindNode(index); + + return element.Value; + } + + protected ListElement FindNode(int index) + { + ListElement? currenElement; + if (index < Count / 2) + { + currenElement = head; + for (int i = 0; i < index; ++i) + { + currenElement = currenElement.Next; + } + } + else + { + currenElement = bottom; + for (int i = Count - 1; i > index; --i) + { + currenElement = currenElement.Previous; + } + } + + return currenElement; + } + + public int Count {get; private set; } + protected ListElement? head = null; + protected ListElement? bottom = null; +} diff --git a/UniqueList/List.Src/List.csproj b/UniqueList/List.Src/List.csproj new file mode 100644 index 0000000..206b89a --- /dev/null +++ b/UniqueList/List.Src/List.csproj @@ -0,0 +1,10 @@ + + + + Exe + net8.0 + enable + enable + + + diff --git a/UniqueList/List.Src/OutOfRangeException.cs b/UniqueList/List.Src/OutOfRangeException.cs new file mode 100644 index 0000000..d7ea64d --- /dev/null +++ b/UniqueList/List.Src/OutOfRangeException.cs @@ -0,0 +1,9 @@ +namespace Lists; + +public class OutOfRangeException : Exception +{ + public OutOfRangeException() { } + public OutOfRangeException(string message) : base(message) { } + + public OutOfRangeException(string message, Exception innerException) : base(message, innerException) { } +} diff --git a/UniqueList/List.Src/Program.cs b/UniqueList/List.Src/Program.cs new file mode 100644 index 0000000..7cd323b --- /dev/null +++ b/UniqueList/List.Src/Program.cs @@ -0,0 +1,138 @@ +using Lists; + + + +class Program +{ + public static void Main() + { + string options = """ + What kind of list do you want to create? Write number to console to choose + 0 - List + 1 - UniqueList + """; + + Console.WriteLine(options); + int listType; + while (!int.TryParse(Console.ReadLine(), out listType) || listType > 1 || listType < 0) + { + Console.WriteLine("Incorrect input"); + Console.Write(options); + } + Console.WriteLine(); + + IList list; + if (listType == 0) + { + list = new List(); + } + else + { + list = new UniqueList(); + } + + bool running = true; + while (running) + { + options = """ + 0 - Exit + 1 - Add element to list + 2 - Insert element to list + 3 - Remove element from list + 4 - Print list + Write number to console to choose option + """; + + Console.WriteLine(options); + + int option; + while (!int.TryParse(Console.ReadLine(), out option) || option > 4 || option < 0) + { + Console.WriteLine("Incorrect input"); + Console.WriteLine(options); + } + + switch (option) + { + case 0: + { + running = false; + break; + } + case 1: + { + var value = UserInputTryParse("Write value you want to add"); + try + { + list.Add(value); + } + catch (ElementExistsException) + { + Console.WriteLine("You have already added this element earlier"); + } + break; + } + case 2: + { + var index = UserInputTryParse("Write an index where you want to insert an element"); + var value = UserInputTryParse("Write value you want to insert"); + + try + { + list.Insert(index, value); + } + catch (OutOfRangeException) + { + Console.WriteLine("Index is out of range"); + } + catch (ElementExistsException) + { + Console.WriteLine("You have already added this element earlier"); + } + break; + } + case 3: + { + var index = UserInputTryParse("Write an index where you want to delete an element"); + try + { + list.RemoveAt(index); + } + catch (OutOfRangeException) + { + Console.WriteLine("Index is out of range"); + } + break; + } + case 4: + { + Console.Write("["); + for (int i = 0; i < list.Count; ++i) + { + Console.Write(list.FindValue(i)); + if (i != list.Count - 1) + { + Console.Write(", "); + } + } + Console.Write("]\n"); + break; + } + } + Console.WriteLine(); + } + } + + private static int UserInputTryParse(string message) + { + Console.WriteLine(message); + int userInput; + while (!int.TryParse(Console.ReadLine(), out userInput)) + { + Console.WriteLine("Incorrect input"); + Console.WriteLine(message); + } + + return userInput; + } +} diff --git a/UniqueList/List.Src/UniqueList.cs b/UniqueList/List.Src/UniqueList.cs new file mode 100644 index 0000000..b21ebef --- /dev/null +++ b/UniqueList/List.Src/UniqueList.cs @@ -0,0 +1,62 @@ +using System.ComponentModel; + +namespace Lists; + +/// +/// Modification of List that doesn't allow you to keep more than one value with the same value +/// +public class UniqueList : List +{ + private bool Contains(int value) + { + if (Count == 0) + { + return false; + } + + var currenElement = head; + for (int i = 0; i < Count; ++i) + { + if (currenElement.Value == value) + { + return true; + } + currenElement = currenElement.Next; + } + + return false; + } + + /// + /// Adds value to the end of list. Throws an exception if element is already in list + /// + /// Value to add + /// Thrown if this element already exists in list + public override void Add(int value) + { + if (Contains(value)) + { + throw new ElementExistsException("Such element has already been added"); + } + + base.Add(value); + } + + /// + /// Method to insert value at given index. Throws an exception if element is already in list + /// + /// Where to insert value + /// Value to insert + /// Exception is thrown if index is less than 0 or + /// bigger than list.Count and it is impossible to insert value + /// Thrown if this element already exists in list + public override void Insert(int index, int value) + { + if (Contains(value)) + { + throw new ElementExistsException("Such element has already been added"); + } + + base.Insert(index, value); + } +} diff --git a/UniqueList/List.Tests/List.Tests.cs b/UniqueList/List.Tests/List.Tests.cs new file mode 100644 index 0000000..5a1d4d4 --- /dev/null +++ b/UniqueList/List.Tests/List.Tests.cs @@ -0,0 +1,70 @@ +namespace List.Tests; +using Lists; + +public class ListTests +{ + [Test] + public void AddTest() + { + var list = new List(); + list.Add(1); + list.Add(2); + list.Add(3); + list.Add(4); + var result = list.ToArray(); + Assert.That(result, Is.EqualTo(new int[4] { 1, 2, 3, 4 })); + } + + [Test] + public void InsertTest() + { + var list = new List(); + list.Insert(0, 1); + list.Insert(1, 2); + list.Insert(2, 3); + list.Insert(3, 4); + var result = list.ToArray(); + Assert.That(result, Is.EqualTo(new int[4] { 1, 2, 3, 4 })); + list.Insert(2, 5); + list.Insert(4, 6); + result = list.ToArray(); + Assert.That(result, Is.EqualTo(new int[6] { 1, 2, 5, 3, 6, 4 })); + } + + [Test] + public void TestOutOfRangeCase() + { + var list = new List(); + Assert.Throws(() => list.Insert(10, 6)); + Assert.Throws(() => list.Insert(-10, 6)); + + Assert.Throws(() => list.RemoveAt(10)); + Assert.Throws(() => list.RemoveAt(-10)); + + Assert.Throws(() => list.FindValue(10)); + Assert.Throws(() => list.FindValue(-10)); + } + + [Test] + public void TestRemove() + { + var list = new List(); + list.Add(1); + list.Add(2); + list.Add(3); + list.Add(4); + list.RemoveAt(2); + var result = list.ToArray(); + Assert.That(result, Is.EqualTo(new int[3] {1, 2, 4})); + list.RemoveAt(0); + result = list.ToArray(); + Assert.That(result, Is.EqualTo(new int[2] {2, 4})); + list.RemoveAt(1); + result = list.ToArray(); + foreach (var item in result) + { + Console.WriteLine(item); + } + Assert.That(result, Is.EqualTo(new int[1] {2})); + } +} diff --git a/UniqueList/List.Tests/List.Tests.csproj b/UniqueList/List.Tests/List.Tests.csproj new file mode 100644 index 0000000..81fde4d --- /dev/null +++ b/UniqueList/List.Tests/List.Tests.csproj @@ -0,0 +1,28 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + + + + diff --git a/UniqueList/List.Tests/UniqueList.Tests.cs b/UniqueList/List.Tests/UniqueList.Tests.cs new file mode 100644 index 0000000..4328df3 --- /dev/null +++ b/UniqueList/List.Tests/UniqueList.Tests.cs @@ -0,0 +1,13 @@ +namespace List.Tests; +using Lists; + +public class UniqueListTests +{ + [Test] + public void TestElementAlreadyExistsException() + { + var uniqueList = new UniqueList(); + uniqueList.Add(1); + Assert.Throws(() => uniqueList.Add(1)); + } +} diff --git a/UniqueList/UniqueList.sln b/UniqueList/UniqueList.sln new file mode 100644 index 0000000..59d2e88 --- /dev/null +++ b/UniqueList/UniqueList.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "List", "List.Src\List.csproj", "{ED63D80C-A9CA-420F-834E-D699C06C8A2F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "List.Tests", "List.Tests\List.Tests.csproj", "{6EC4DA67-6869-4EE6-A493-3AFBE7601FCB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {ED63D80C-A9CA-420F-834E-D699C06C8A2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ED63D80C-A9CA-420F-834E-D699C06C8A2F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ED63D80C-A9CA-420F-834E-D699C06C8A2F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ED63D80C-A9CA-420F-834E-D699C06C8A2F}.Release|Any CPU.Build.0 = Release|Any CPU + {6EC4DA67-6869-4EE6-A493-3AFBE7601FCB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6EC4DA67-6869-4EE6-A493-3AFBE7601FCB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6EC4DA67-6869-4EE6-A493-3AFBE7601FCB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6EC4DA67-6869-4EE6-A493-3AFBE7601FCB}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal