Linked list implementation along with unit testLinked list implementation along with unit test - Round...
What's the output of a record cartridge playing an out-of-speed record
Can I ask the recruiters in my resume to put the reason why I am rejected?
Is it unprofessional to ask if a job posting on GlassDoor is real?
Have astronauts in space suits ever taken selfies? If so, how?
Schoenfled Residua test shows proportionality hazard assumptions holds but Kaplan-Meier plots intersect
Finding angle with pure Geometry.
Why do falling prices hurt debtors?
can i play a electric guitar through a bass amp?
Why, historically, did Gödel think CH was false?
In Japanese, what’s the difference between “Tonari ni” (となりに) and “Tsugi” (つぎ)? When would you use one over the other?
Is it legal for company to use my work email to pretend I still work there?
Do I have a twin with permutated remainders?
Is it important to consider tone, melody, and musical form while writing a song?
The Clique vs. Independent Set Problem
Unknown notation: What do three bars mean?
Pattern match does not work in bash script
What does it mean to describe someone as a butt steak?
Today is the Center
Fully-Firstable Anagram Sets
Accidentally leaked the solution to an assignment, what to do now? (I'm the prof)
How can bays and straits be determined in a procedurally generated map?
What's the point of deactivating Num Lock on login screens?
How to format long polynomial?
Email Account under attack (really) - anything I can do?
Linked list implementation along with unit test
Linked list implementation along with unit test - Round 2Writing to a newly created file, with support for unit testingAll your bases are belong to DijkstraInsert a Node at the Tail of a Linked ListConverting a 2D Array into a 2D Linked ListDoubly-linked list implementation in Python with unit-testsC++11 Singly Linked List with raw pointersPersistent List with constexpr and pointersLinked List using templates and smart pointersLeetcode #146. LRUCache solution in Java (Doubly Linked List + HashMap)Linked list implementation along with unit test - Round 2
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ margin-bottom:0;
}
$begingroup$
I've already made all the changes suggested here. Here is the link for round 2: Linked list implementation along with unit test [Round 2]
I want to see how other people think of my code, so here it goes. This is my first time writing a unit test. I'm wondering if there needs to be more tests for the LinkedList class and also if I'm writing them correctly.
I've made the Node class public so I can use it for a binary tree implementation later.
namespace DataStructuresAndAlgorithms.DataStructures
{
public class Node<T>
{
public T Data { get; set; }
public Node<T> Next { get; set; }
public Node<T> Previous { get; set; }
public Node() { }
public Node(T t)
{
Data = t;
}
}
}
Implementation
using System;
using System.Collections.Generic;
namespace DataStructuresAndAlgorithms.DataStructures
{
public class LinkedList<T>
{
public Node<T> Head { get; private set; }
public Node<T> Tail { get; private set; }
public LinkedList(Node<T> node)
{
Head = node;
Tail = node;
}
public void AddToFirst(Node<T> toAdd)
{
toAdd.Next = Head;
Head = toAdd;
}
public void AddToLast(Node<T> toAdd)
{
Tail.Next = toAdd;
Tail = toAdd;
}
public void RemoveFirst()
{
Head = Head.Next;
}
public void RemoveLast()
{
var pointer = Head;
while (pointer.Next != Tail)
{
pointer = pointer.Next;
}
// pointer is now before Tail
Tail = pointer;
Tail.Next = null;
}
public IEnumerator<Node<T>> GetEnumerator()
{
var pointer = Head;
while (pointer != null)
{
yield return pointer;
pointer = pointer.Next;
}
}
}
}
Unit Test
using System;
using Xunit;
using DataStructuresAndAlgorithms.DataStructures;
namespace DataStructuresAndAlgorithms.DataStructures.Tests
{
public class LinkedListTest
{
[Fact]
public void AddToFirst_Node_Should_Become_Head()
{
// Arrange
var myLinkedList = new LinkedList<int>(new Node<int>(45));
// Act
var nodeToAdd = new Node<int>(67);
myLinkedList.AddToFirst(nodeToAdd);
// Assert
var theNode = GetNodeFromList<int>(myLinkedList, nodeToAdd);
Assert.Equal(nodeToAdd, theNode);
Assert.Equal(45, theNode.Next.Data);
}
[Fact]
public void AddToLast_Node_Should_Become_Tail()
{
// Arrange
var myLinkedList = new LinkedList<int>(new Node<int>(35));
// Act
var nodeToAdd = new Node<int>(14);
myLinkedList.AddToLast(nodeToAdd);
// Assert
var theNode = GetNodeFromList<int>(myLinkedList, nodeToAdd);
Assert.Equal(nodeToAdd, theNode);
}
[Fact]
public void RemoveFirst_Next_Node_Should_Be_Head()
{
// Arrange
var myLinkedList = new LinkedList<int>(new Node<int>(777));
var node1 = new Node<int>(1);
myLinkedList.AddToLast(node1);
var node2 = new Node<int>(2);
myLinkedList.AddToLast(node2);
var node3 = new Node<int>(3);
myLinkedList.AddToLast(node3);
// Act
myLinkedList.RemoveFirst();
// Assert
var theNode = GetNodeFromList<int>(myLinkedList, node1);
Assert.Equal(node1, myLinkedList.Head);
}
[Fact]
public void RemoveLast_Next_Node_Should_Be_Tail()
{
// Arrange
var myLinkedList = new LinkedList<int>(new Node<int>(777));
var node1 = new Node<int>(1);
myLinkedList.AddToLast(node1);
var node2 = new Node<int>(2);
myLinkedList.AddToLast(node2);
var node3 = new Node<int>(3);
myLinkedList.AddToLast(node3);
// Act
myLinkedList.RemoveLast();
// Assert
var theNode = GetNodeFromList<int>(myLinkedList, node2);
Assert.Equal(node2, myLinkedList.Tail);
}
public static Node<T> GetNodeFromList<T>(LinkedList<T> someLinkedList, Node<T> someNode) where T : struct
{
using (var itr = someLinkedList.GetEnumerator())
{
while (itr.Current != someNode)
{
itr.MoveNext();
}
return itr.Current;
}
}
}
}
Presentation
using System;
using System.Collections;
using DataStructuresAndAlgorithms.DataStructures;
namespace DataStructuresAndAlgorithms.Presentation.Console
{
class Program
{
static void Main(string[] args)
{
RunNode();
System.Console.WriteLine();
RunLinkedList();
}
static void RunNode()
{
System.Console.WriteLine("Running the Node class");
System.Console.WriteLine("----------------------");
var myNode = new Node<int>(32);
System.Console.WriteLine(myNode.Data);
}
static void RunLinkedList()
{
System.Console.WriteLine("Running the LinkedList class");
System.Console.WriteLine("----------------------------");
var myLinkedList = new LinkedList<int>(new Node<int>(99));
myLinkedList.AddToFirst(new Node<int>(56));
myLinkedList.AddToFirst(new Node<int>(23));
myLinkedList.AddToFirst(new Node<int>(33));
myLinkedList.AddToLast(new Node<int>(8888));
myLinkedList.RemoveLast();
myLinkedList.RemoveFirst();
System.Console.WriteLine("HEAD = " + myLinkedList.Head.Data);
System.Console.WriteLine("TAIL = " + myLinkedList.Tail.Data);
using (var linkedListEnumerator = myLinkedList.GetEnumerator())
{
while (linkedListEnumerator.MoveNext())
{
System.Console.WriteLine(linkedListEnumerator.Current.Data);
}
}
}
}
}
```
c# beginner linked-list unit-testing
$endgroup$
add a comment |
$begingroup$
I've already made all the changes suggested here. Here is the link for round 2: Linked list implementation along with unit test [Round 2]
I want to see how other people think of my code, so here it goes. This is my first time writing a unit test. I'm wondering if there needs to be more tests for the LinkedList class and also if I'm writing them correctly.
I've made the Node class public so I can use it for a binary tree implementation later.
namespace DataStructuresAndAlgorithms.DataStructures
{
public class Node<T>
{
public T Data { get; set; }
public Node<T> Next { get; set; }
public Node<T> Previous { get; set; }
public Node() { }
public Node(T t)
{
Data = t;
}
}
}
Implementation
using System;
using System.Collections.Generic;
namespace DataStructuresAndAlgorithms.DataStructures
{
public class LinkedList<T>
{
public Node<T> Head { get; private set; }
public Node<T> Tail { get; private set; }
public LinkedList(Node<T> node)
{
Head = node;
Tail = node;
}
public void AddToFirst(Node<T> toAdd)
{
toAdd.Next = Head;
Head = toAdd;
}
public void AddToLast(Node<T> toAdd)
{
Tail.Next = toAdd;
Tail = toAdd;
}
public void RemoveFirst()
{
Head = Head.Next;
}
public void RemoveLast()
{
var pointer = Head;
while (pointer.Next != Tail)
{
pointer = pointer.Next;
}
// pointer is now before Tail
Tail = pointer;
Tail.Next = null;
}
public IEnumerator<Node<T>> GetEnumerator()
{
var pointer = Head;
while (pointer != null)
{
yield return pointer;
pointer = pointer.Next;
}
}
}
}
Unit Test
using System;
using Xunit;
using DataStructuresAndAlgorithms.DataStructures;
namespace DataStructuresAndAlgorithms.DataStructures.Tests
{
public class LinkedListTest
{
[Fact]
public void AddToFirst_Node_Should_Become_Head()
{
// Arrange
var myLinkedList = new LinkedList<int>(new Node<int>(45));
// Act
var nodeToAdd = new Node<int>(67);
myLinkedList.AddToFirst(nodeToAdd);
// Assert
var theNode = GetNodeFromList<int>(myLinkedList, nodeToAdd);
Assert.Equal(nodeToAdd, theNode);
Assert.Equal(45, theNode.Next.Data);
}
[Fact]
public void AddToLast_Node_Should_Become_Tail()
{
// Arrange
var myLinkedList = new LinkedList<int>(new Node<int>(35));
// Act
var nodeToAdd = new Node<int>(14);
myLinkedList.AddToLast(nodeToAdd);
// Assert
var theNode = GetNodeFromList<int>(myLinkedList, nodeToAdd);
Assert.Equal(nodeToAdd, theNode);
}
[Fact]
public void RemoveFirst_Next_Node_Should_Be_Head()
{
// Arrange
var myLinkedList = new LinkedList<int>(new Node<int>(777));
var node1 = new Node<int>(1);
myLinkedList.AddToLast(node1);
var node2 = new Node<int>(2);
myLinkedList.AddToLast(node2);
var node3 = new Node<int>(3);
myLinkedList.AddToLast(node3);
// Act
myLinkedList.RemoveFirst();
// Assert
var theNode = GetNodeFromList<int>(myLinkedList, node1);
Assert.Equal(node1, myLinkedList.Head);
}
[Fact]
public void RemoveLast_Next_Node_Should_Be_Tail()
{
// Arrange
var myLinkedList = new LinkedList<int>(new Node<int>(777));
var node1 = new Node<int>(1);
myLinkedList.AddToLast(node1);
var node2 = new Node<int>(2);
myLinkedList.AddToLast(node2);
var node3 = new Node<int>(3);
myLinkedList.AddToLast(node3);
// Act
myLinkedList.RemoveLast();
// Assert
var theNode = GetNodeFromList<int>(myLinkedList, node2);
Assert.Equal(node2, myLinkedList.Tail);
}
public static Node<T> GetNodeFromList<T>(LinkedList<T> someLinkedList, Node<T> someNode) where T : struct
{
using (var itr = someLinkedList.GetEnumerator())
{
while (itr.Current != someNode)
{
itr.MoveNext();
}
return itr.Current;
}
}
}
}
Presentation
using System;
using System.Collections;
using DataStructuresAndAlgorithms.DataStructures;
namespace DataStructuresAndAlgorithms.Presentation.Console
{
class Program
{
static void Main(string[] args)
{
RunNode();
System.Console.WriteLine();
RunLinkedList();
}
static void RunNode()
{
System.Console.WriteLine("Running the Node class");
System.Console.WriteLine("----------------------");
var myNode = new Node<int>(32);
System.Console.WriteLine(myNode.Data);
}
static void RunLinkedList()
{
System.Console.WriteLine("Running the LinkedList class");
System.Console.WriteLine("----------------------------");
var myLinkedList = new LinkedList<int>(new Node<int>(99));
myLinkedList.AddToFirst(new Node<int>(56));
myLinkedList.AddToFirst(new Node<int>(23));
myLinkedList.AddToFirst(new Node<int>(33));
myLinkedList.AddToLast(new Node<int>(8888));
myLinkedList.RemoveLast();
myLinkedList.RemoveFirst();
System.Console.WriteLine("HEAD = " + myLinkedList.Head.Data);
System.Console.WriteLine("TAIL = " + myLinkedList.Tail.Data);
using (var linkedListEnumerator = myLinkedList.GetEnumerator())
{
while (linkedListEnumerator.MoveNext())
{
System.Console.WriteLine(linkedListEnumerator.Current.Data);
}
}
}
}
}
```
c# beginner linked-list unit-testing
$endgroup$
add a comment |
$begingroup$
I've already made all the changes suggested here. Here is the link for round 2: Linked list implementation along with unit test [Round 2]
I want to see how other people think of my code, so here it goes. This is my first time writing a unit test. I'm wondering if there needs to be more tests for the LinkedList class and also if I'm writing them correctly.
I've made the Node class public so I can use it for a binary tree implementation later.
namespace DataStructuresAndAlgorithms.DataStructures
{
public class Node<T>
{
public T Data { get; set; }
public Node<T> Next { get; set; }
public Node<T> Previous { get; set; }
public Node() { }
public Node(T t)
{
Data = t;
}
}
}
Implementation
using System;
using System.Collections.Generic;
namespace DataStructuresAndAlgorithms.DataStructures
{
public class LinkedList<T>
{
public Node<T> Head { get; private set; }
public Node<T> Tail { get; private set; }
public LinkedList(Node<T> node)
{
Head = node;
Tail = node;
}
public void AddToFirst(Node<T> toAdd)
{
toAdd.Next = Head;
Head = toAdd;
}
public void AddToLast(Node<T> toAdd)
{
Tail.Next = toAdd;
Tail = toAdd;
}
public void RemoveFirst()
{
Head = Head.Next;
}
public void RemoveLast()
{
var pointer = Head;
while (pointer.Next != Tail)
{
pointer = pointer.Next;
}
// pointer is now before Tail
Tail = pointer;
Tail.Next = null;
}
public IEnumerator<Node<T>> GetEnumerator()
{
var pointer = Head;
while (pointer != null)
{
yield return pointer;
pointer = pointer.Next;
}
}
}
}
Unit Test
using System;
using Xunit;
using DataStructuresAndAlgorithms.DataStructures;
namespace DataStructuresAndAlgorithms.DataStructures.Tests
{
public class LinkedListTest
{
[Fact]
public void AddToFirst_Node_Should_Become_Head()
{
// Arrange
var myLinkedList = new LinkedList<int>(new Node<int>(45));
// Act
var nodeToAdd = new Node<int>(67);
myLinkedList.AddToFirst(nodeToAdd);
// Assert
var theNode = GetNodeFromList<int>(myLinkedList, nodeToAdd);
Assert.Equal(nodeToAdd, theNode);
Assert.Equal(45, theNode.Next.Data);
}
[Fact]
public void AddToLast_Node_Should_Become_Tail()
{
// Arrange
var myLinkedList = new LinkedList<int>(new Node<int>(35));
// Act
var nodeToAdd = new Node<int>(14);
myLinkedList.AddToLast(nodeToAdd);
// Assert
var theNode = GetNodeFromList<int>(myLinkedList, nodeToAdd);
Assert.Equal(nodeToAdd, theNode);
}
[Fact]
public void RemoveFirst_Next_Node_Should_Be_Head()
{
// Arrange
var myLinkedList = new LinkedList<int>(new Node<int>(777));
var node1 = new Node<int>(1);
myLinkedList.AddToLast(node1);
var node2 = new Node<int>(2);
myLinkedList.AddToLast(node2);
var node3 = new Node<int>(3);
myLinkedList.AddToLast(node3);
// Act
myLinkedList.RemoveFirst();
// Assert
var theNode = GetNodeFromList<int>(myLinkedList, node1);
Assert.Equal(node1, myLinkedList.Head);
}
[Fact]
public void RemoveLast_Next_Node_Should_Be_Tail()
{
// Arrange
var myLinkedList = new LinkedList<int>(new Node<int>(777));
var node1 = new Node<int>(1);
myLinkedList.AddToLast(node1);
var node2 = new Node<int>(2);
myLinkedList.AddToLast(node2);
var node3 = new Node<int>(3);
myLinkedList.AddToLast(node3);
// Act
myLinkedList.RemoveLast();
// Assert
var theNode = GetNodeFromList<int>(myLinkedList, node2);
Assert.Equal(node2, myLinkedList.Tail);
}
public static Node<T> GetNodeFromList<T>(LinkedList<T> someLinkedList, Node<T> someNode) where T : struct
{
using (var itr = someLinkedList.GetEnumerator())
{
while (itr.Current != someNode)
{
itr.MoveNext();
}
return itr.Current;
}
}
}
}
Presentation
using System;
using System.Collections;
using DataStructuresAndAlgorithms.DataStructures;
namespace DataStructuresAndAlgorithms.Presentation.Console
{
class Program
{
static void Main(string[] args)
{
RunNode();
System.Console.WriteLine();
RunLinkedList();
}
static void RunNode()
{
System.Console.WriteLine("Running the Node class");
System.Console.WriteLine("----------------------");
var myNode = new Node<int>(32);
System.Console.WriteLine(myNode.Data);
}
static void RunLinkedList()
{
System.Console.WriteLine("Running the LinkedList class");
System.Console.WriteLine("----------------------------");
var myLinkedList = new LinkedList<int>(new Node<int>(99));
myLinkedList.AddToFirst(new Node<int>(56));
myLinkedList.AddToFirst(new Node<int>(23));
myLinkedList.AddToFirst(new Node<int>(33));
myLinkedList.AddToLast(new Node<int>(8888));
myLinkedList.RemoveLast();
myLinkedList.RemoveFirst();
System.Console.WriteLine("HEAD = " + myLinkedList.Head.Data);
System.Console.WriteLine("TAIL = " + myLinkedList.Tail.Data);
using (var linkedListEnumerator = myLinkedList.GetEnumerator())
{
while (linkedListEnumerator.MoveNext())
{
System.Console.WriteLine(linkedListEnumerator.Current.Data);
}
}
}
}
}
```
c# beginner linked-list unit-testing
$endgroup$
I've already made all the changes suggested here. Here is the link for round 2: Linked list implementation along with unit test [Round 2]
I want to see how other people think of my code, so here it goes. This is my first time writing a unit test. I'm wondering if there needs to be more tests for the LinkedList class and also if I'm writing them correctly.
I've made the Node class public so I can use it for a binary tree implementation later.
namespace DataStructuresAndAlgorithms.DataStructures
{
public class Node<T>
{
public T Data { get; set; }
public Node<T> Next { get; set; }
public Node<T> Previous { get; set; }
public Node() { }
public Node(T t)
{
Data = t;
}
}
}
Implementation
using System;
using System.Collections.Generic;
namespace DataStructuresAndAlgorithms.DataStructures
{
public class LinkedList<T>
{
public Node<T> Head { get; private set; }
public Node<T> Tail { get; private set; }
public LinkedList(Node<T> node)
{
Head = node;
Tail = node;
}
public void AddToFirst(Node<T> toAdd)
{
toAdd.Next = Head;
Head = toAdd;
}
public void AddToLast(Node<T> toAdd)
{
Tail.Next = toAdd;
Tail = toAdd;
}
public void RemoveFirst()
{
Head = Head.Next;
}
public void RemoveLast()
{
var pointer = Head;
while (pointer.Next != Tail)
{
pointer = pointer.Next;
}
// pointer is now before Tail
Tail = pointer;
Tail.Next = null;
}
public IEnumerator<Node<T>> GetEnumerator()
{
var pointer = Head;
while (pointer != null)
{
yield return pointer;
pointer = pointer.Next;
}
}
}
}
Unit Test
using System;
using Xunit;
using DataStructuresAndAlgorithms.DataStructures;
namespace DataStructuresAndAlgorithms.DataStructures.Tests
{
public class LinkedListTest
{
[Fact]
public void AddToFirst_Node_Should_Become_Head()
{
// Arrange
var myLinkedList = new LinkedList<int>(new Node<int>(45));
// Act
var nodeToAdd = new Node<int>(67);
myLinkedList.AddToFirst(nodeToAdd);
// Assert
var theNode = GetNodeFromList<int>(myLinkedList, nodeToAdd);
Assert.Equal(nodeToAdd, theNode);
Assert.Equal(45, theNode.Next.Data);
}
[Fact]
public void AddToLast_Node_Should_Become_Tail()
{
// Arrange
var myLinkedList = new LinkedList<int>(new Node<int>(35));
// Act
var nodeToAdd = new Node<int>(14);
myLinkedList.AddToLast(nodeToAdd);
// Assert
var theNode = GetNodeFromList<int>(myLinkedList, nodeToAdd);
Assert.Equal(nodeToAdd, theNode);
}
[Fact]
public void RemoveFirst_Next_Node_Should_Be_Head()
{
// Arrange
var myLinkedList = new LinkedList<int>(new Node<int>(777));
var node1 = new Node<int>(1);
myLinkedList.AddToLast(node1);
var node2 = new Node<int>(2);
myLinkedList.AddToLast(node2);
var node3 = new Node<int>(3);
myLinkedList.AddToLast(node3);
// Act
myLinkedList.RemoveFirst();
// Assert
var theNode = GetNodeFromList<int>(myLinkedList, node1);
Assert.Equal(node1, myLinkedList.Head);
}
[Fact]
public void RemoveLast_Next_Node_Should_Be_Tail()
{
// Arrange
var myLinkedList = new LinkedList<int>(new Node<int>(777));
var node1 = new Node<int>(1);
myLinkedList.AddToLast(node1);
var node2 = new Node<int>(2);
myLinkedList.AddToLast(node2);
var node3 = new Node<int>(3);
myLinkedList.AddToLast(node3);
// Act
myLinkedList.RemoveLast();
// Assert
var theNode = GetNodeFromList<int>(myLinkedList, node2);
Assert.Equal(node2, myLinkedList.Tail);
}
public static Node<T> GetNodeFromList<T>(LinkedList<T> someLinkedList, Node<T> someNode) where T : struct
{
using (var itr = someLinkedList.GetEnumerator())
{
while (itr.Current != someNode)
{
itr.MoveNext();
}
return itr.Current;
}
}
}
}
Presentation
using System;
using System.Collections;
using DataStructuresAndAlgorithms.DataStructures;
namespace DataStructuresAndAlgorithms.Presentation.Console
{
class Program
{
static void Main(string[] args)
{
RunNode();
System.Console.WriteLine();
RunLinkedList();
}
static void RunNode()
{
System.Console.WriteLine("Running the Node class");
System.Console.WriteLine("----------------------");
var myNode = new Node<int>(32);
System.Console.WriteLine(myNode.Data);
}
static void RunLinkedList()
{
System.Console.WriteLine("Running the LinkedList class");
System.Console.WriteLine("----------------------------");
var myLinkedList = new LinkedList<int>(new Node<int>(99));
myLinkedList.AddToFirst(new Node<int>(56));
myLinkedList.AddToFirst(new Node<int>(23));
myLinkedList.AddToFirst(new Node<int>(33));
myLinkedList.AddToLast(new Node<int>(8888));
myLinkedList.RemoveLast();
myLinkedList.RemoveFirst();
System.Console.WriteLine("HEAD = " + myLinkedList.Head.Data);
System.Console.WriteLine("TAIL = " + myLinkedList.Tail.Data);
using (var linkedListEnumerator = myLinkedList.GetEnumerator())
{
while (linkedListEnumerator.MoveNext())
{
System.Console.WriteLine(linkedListEnumerator.Current.Data);
}
}
}
}
}
```
c# beginner linked-list unit-testing
c# beginner linked-list unit-testing
edited Mar 29 at 21:12
feature_creep
asked Mar 28 at 22:44
feature_creepfeature_creep
585
585
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
$begingroup$
I've made the Node class public so I can use it for a binary tree implementation later
I don't think you can use this Node
type as a node in a binary tree, because nodes in binary trees typically has references to other nodes like Parent
, Left
and Right
. So IMO keep this Node
class as a dedicated node type for this linked list:
public class LinkedList<T>
{
class Node
{
public T Data { get; }
public Node Next { get; set; }
public Node Previous { get; set; }
public Node(T data)
{
Data = data;
}
}
In this way you can skip the type parameter on the Node
class. As shown above I've also made the Node
class immutable for the Data
property and hence no default constructor. It's easier to maintain, if you know that there is a one-to-one relationship between a data object and a Node
.
public Node<T> Head { get; private set; }
public Node<T> Tail { get; private set; }
It's fine to have a public Head
and Tail
property, but they should be of type T
and not Node
. The client should be agnostic about the inner implementation of your list and only "communicate" objects of type T
with it:
public T Head => _headNode.Data; // TODO check for null
public T Tail => _tailNode.Data; // TODO check for null
This will require that you have private nodes for head and tail as illustrated above.
public LinkedList(Node<T> node)
{
Head = node;
Tail = node;
}
Having a one and only constructor that takes a node (or item) is not a good idea, because you often want to instantiate an empty list and provide it as argument to a method or something like that. So your list should have a default constructor with no arguments:
public LinkedList()
{
}
You could also consider to have a constructor with a vector of items:
public LinkedList(IEnumerable<T> items)
{
foreach (var item in items)
{
AddTail(item);
}
}
public void AddToFirst(Node toAdd) {...}
public void AddToLast(Node toAdd) {...}
You would typically call these methods AddHead
and AddTail
:
public void AddHead(T item) {...}
public void AddTail(T item) {...}
as you would call RemoveFirst()
RemoveHead()
...
public void AddToFirst(Node<T> toAdd)
{
toAdd.Next = Head;
Head = toAdd;
}
public void AddToLast(Node<T> toAdd)
{
Tail.Next = toAdd; //OBS: This will fail if Tail is null!
Tail = toAdd;
}
Your Node<T>
class has a Previous
property, why don't you use that (doubly linked list)?
public void RemoveFirst()
{
Head = Head.Next;
}
This will fail, if Head
is null
.
public void RemoveLast()
{
var pointer = Head;
while (pointer.Next != Tail)
{
pointer = pointer.Next;
}
// pointer is now before Tail
Tail = pointer;
Tail.Next = null;
}
Why iterate through the entire list, when you have a reference to the last node in Tail
?:
public void RemoveLast()
{
if (Tail != null)
{
Tail = Tail.Previous;
Tail.Next = null;
}
}
You could consider to return the Data
value from the removed nodes.
public T RemoveLast() {...}
public IEnumerator<Node<T>> GetEnumerator()
{
var pointer = Head;
while (pointer != null)
{
yield return pointer;
pointer = pointer.Next;
}
}
It's fine to provide an enumerator. But it would be better to implement the IEnumerable<T>
interface instead - where T is the T
from your list - not Node<T>
.
If you do that, instead of this
using (var linkedListEnumerator = myLinkedList.GetEnumerator())
{
while (linkedListEnumerator.MoveNext())
{
Console.WriteLine(linkedListEnumerator.Current.Data);
}
}
you would be able to do
foreach (var item in myLinkedList)
{
Console.WriteLine(item);
}
And besides that, by implementing IEnumerable<T>
, you'll be able to use LINQ extensions on the list. (see also VisualMelons comment).
Consider to implement this:
public bool Remove(T item)
{
// TODO: implement this
return <wasRemoved>;
}
You could try to implement the above and make a new post with an updated version with unit tests and we could then review that... :-)
Your use case should look as something like:
void RunLinkedList()
{
Console.WriteLine("Running the LinkedList class");
Console.WriteLine("----------------------------");
var myLinkedList = new LinkedList<int>();
myLinkedList.AddHead(99);
myLinkedList.AddHead(56);
myLinkedList.AddHead(23);
myLinkedList.AddHead(33);
myLinkedList.AddTail(8888);
myLinkedList.RemoveTail();
myLinkedList.RemoveHead();
Console.WriteLine("HEAD = " + myLinkedList.Head);
Console.WriteLine("TAIL = " + myLinkedList.Tail);
foreach (var item in myLinkedList)
{
Console.WriteLine(item);
}
}
$endgroup$
1
$begingroup$
With your suggestion,public T RemoveLast() {...}
, doesn't it violate Command-Query Separation? RemoveLast() modifies state. Is It okay to break the rule sometimes?
$endgroup$
– feature_creep
Mar 29 at 14:47
1
$begingroup$
+1; sadly (IMO) you can already useforeach
on the OP's class, but properly implementingIEnumerable<T>
will facilitate much more.
$endgroup$
– VisualMelon
Mar 29 at 14:56
$begingroup$
@VisualMelon: You're right. I know you can, but what I intended to show was that the Enumerator enumerates theT
's and not theNode<T>
s. By implementing IEnumerable<T> you'll be able to use the standard Linq extensions etc.
$endgroup$
– Henrik Hansen
Mar 29 at 15:08
$begingroup$
@feature_creep: IMO CQS is about not changing the object (the list) when querying it. Here I do the opposite: changing the object and provide the "change" to the client - it's not a query. It's a little different.
$endgroup$
– Henrik Hansen
Mar 29 at 15:12
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f216453%2flinked-list-implementation-along-with-unit-test%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
I've made the Node class public so I can use it for a binary tree implementation later
I don't think you can use this Node
type as a node in a binary tree, because nodes in binary trees typically has references to other nodes like Parent
, Left
and Right
. So IMO keep this Node
class as a dedicated node type for this linked list:
public class LinkedList<T>
{
class Node
{
public T Data { get; }
public Node Next { get; set; }
public Node Previous { get; set; }
public Node(T data)
{
Data = data;
}
}
In this way you can skip the type parameter on the Node
class. As shown above I've also made the Node
class immutable for the Data
property and hence no default constructor. It's easier to maintain, if you know that there is a one-to-one relationship between a data object and a Node
.
public Node<T> Head { get; private set; }
public Node<T> Tail { get; private set; }
It's fine to have a public Head
and Tail
property, but they should be of type T
and not Node
. The client should be agnostic about the inner implementation of your list and only "communicate" objects of type T
with it:
public T Head => _headNode.Data; // TODO check for null
public T Tail => _tailNode.Data; // TODO check for null
This will require that you have private nodes for head and tail as illustrated above.
public LinkedList(Node<T> node)
{
Head = node;
Tail = node;
}
Having a one and only constructor that takes a node (or item) is not a good idea, because you often want to instantiate an empty list and provide it as argument to a method or something like that. So your list should have a default constructor with no arguments:
public LinkedList()
{
}
You could also consider to have a constructor with a vector of items:
public LinkedList(IEnumerable<T> items)
{
foreach (var item in items)
{
AddTail(item);
}
}
public void AddToFirst(Node toAdd) {...}
public void AddToLast(Node toAdd) {...}
You would typically call these methods AddHead
and AddTail
:
public void AddHead(T item) {...}
public void AddTail(T item) {...}
as you would call RemoveFirst()
RemoveHead()
...
public void AddToFirst(Node<T> toAdd)
{
toAdd.Next = Head;
Head = toAdd;
}
public void AddToLast(Node<T> toAdd)
{
Tail.Next = toAdd; //OBS: This will fail if Tail is null!
Tail = toAdd;
}
Your Node<T>
class has a Previous
property, why don't you use that (doubly linked list)?
public void RemoveFirst()
{
Head = Head.Next;
}
This will fail, if Head
is null
.
public void RemoveLast()
{
var pointer = Head;
while (pointer.Next != Tail)
{
pointer = pointer.Next;
}
// pointer is now before Tail
Tail = pointer;
Tail.Next = null;
}
Why iterate through the entire list, when you have a reference to the last node in Tail
?:
public void RemoveLast()
{
if (Tail != null)
{
Tail = Tail.Previous;
Tail.Next = null;
}
}
You could consider to return the Data
value from the removed nodes.
public T RemoveLast() {...}
public IEnumerator<Node<T>> GetEnumerator()
{
var pointer = Head;
while (pointer != null)
{
yield return pointer;
pointer = pointer.Next;
}
}
It's fine to provide an enumerator. But it would be better to implement the IEnumerable<T>
interface instead - where T is the T
from your list - not Node<T>
.
If you do that, instead of this
using (var linkedListEnumerator = myLinkedList.GetEnumerator())
{
while (linkedListEnumerator.MoveNext())
{
Console.WriteLine(linkedListEnumerator.Current.Data);
}
}
you would be able to do
foreach (var item in myLinkedList)
{
Console.WriteLine(item);
}
And besides that, by implementing IEnumerable<T>
, you'll be able to use LINQ extensions on the list. (see also VisualMelons comment).
Consider to implement this:
public bool Remove(T item)
{
// TODO: implement this
return <wasRemoved>;
}
You could try to implement the above and make a new post with an updated version with unit tests and we could then review that... :-)
Your use case should look as something like:
void RunLinkedList()
{
Console.WriteLine("Running the LinkedList class");
Console.WriteLine("----------------------------");
var myLinkedList = new LinkedList<int>();
myLinkedList.AddHead(99);
myLinkedList.AddHead(56);
myLinkedList.AddHead(23);
myLinkedList.AddHead(33);
myLinkedList.AddTail(8888);
myLinkedList.RemoveTail();
myLinkedList.RemoveHead();
Console.WriteLine("HEAD = " + myLinkedList.Head);
Console.WriteLine("TAIL = " + myLinkedList.Tail);
foreach (var item in myLinkedList)
{
Console.WriteLine(item);
}
}
$endgroup$
1
$begingroup$
With your suggestion,public T RemoveLast() {...}
, doesn't it violate Command-Query Separation? RemoveLast() modifies state. Is It okay to break the rule sometimes?
$endgroup$
– feature_creep
Mar 29 at 14:47
1
$begingroup$
+1; sadly (IMO) you can already useforeach
on the OP's class, but properly implementingIEnumerable<T>
will facilitate much more.
$endgroup$
– VisualMelon
Mar 29 at 14:56
$begingroup$
@VisualMelon: You're right. I know you can, but what I intended to show was that the Enumerator enumerates theT
's and not theNode<T>
s. By implementing IEnumerable<T> you'll be able to use the standard Linq extensions etc.
$endgroup$
– Henrik Hansen
Mar 29 at 15:08
$begingroup$
@feature_creep: IMO CQS is about not changing the object (the list) when querying it. Here I do the opposite: changing the object and provide the "change" to the client - it's not a query. It's a little different.
$endgroup$
– Henrik Hansen
Mar 29 at 15:12
add a comment |
$begingroup$
I've made the Node class public so I can use it for a binary tree implementation later
I don't think you can use this Node
type as a node in a binary tree, because nodes in binary trees typically has references to other nodes like Parent
, Left
and Right
. So IMO keep this Node
class as a dedicated node type for this linked list:
public class LinkedList<T>
{
class Node
{
public T Data { get; }
public Node Next { get; set; }
public Node Previous { get; set; }
public Node(T data)
{
Data = data;
}
}
In this way you can skip the type parameter on the Node
class. As shown above I've also made the Node
class immutable for the Data
property and hence no default constructor. It's easier to maintain, if you know that there is a one-to-one relationship between a data object and a Node
.
public Node<T> Head { get; private set; }
public Node<T> Tail { get; private set; }
It's fine to have a public Head
and Tail
property, but they should be of type T
and not Node
. The client should be agnostic about the inner implementation of your list and only "communicate" objects of type T
with it:
public T Head => _headNode.Data; // TODO check for null
public T Tail => _tailNode.Data; // TODO check for null
This will require that you have private nodes for head and tail as illustrated above.
public LinkedList(Node<T> node)
{
Head = node;
Tail = node;
}
Having a one and only constructor that takes a node (or item) is not a good idea, because you often want to instantiate an empty list and provide it as argument to a method or something like that. So your list should have a default constructor with no arguments:
public LinkedList()
{
}
You could also consider to have a constructor with a vector of items:
public LinkedList(IEnumerable<T> items)
{
foreach (var item in items)
{
AddTail(item);
}
}
public void AddToFirst(Node toAdd) {...}
public void AddToLast(Node toAdd) {...}
You would typically call these methods AddHead
and AddTail
:
public void AddHead(T item) {...}
public void AddTail(T item) {...}
as you would call RemoveFirst()
RemoveHead()
...
public void AddToFirst(Node<T> toAdd)
{
toAdd.Next = Head;
Head = toAdd;
}
public void AddToLast(Node<T> toAdd)
{
Tail.Next = toAdd; //OBS: This will fail if Tail is null!
Tail = toAdd;
}
Your Node<T>
class has a Previous
property, why don't you use that (doubly linked list)?
public void RemoveFirst()
{
Head = Head.Next;
}
This will fail, if Head
is null
.
public void RemoveLast()
{
var pointer = Head;
while (pointer.Next != Tail)
{
pointer = pointer.Next;
}
// pointer is now before Tail
Tail = pointer;
Tail.Next = null;
}
Why iterate through the entire list, when you have a reference to the last node in Tail
?:
public void RemoveLast()
{
if (Tail != null)
{
Tail = Tail.Previous;
Tail.Next = null;
}
}
You could consider to return the Data
value from the removed nodes.
public T RemoveLast() {...}
public IEnumerator<Node<T>> GetEnumerator()
{
var pointer = Head;
while (pointer != null)
{
yield return pointer;
pointer = pointer.Next;
}
}
It's fine to provide an enumerator. But it would be better to implement the IEnumerable<T>
interface instead - where T is the T
from your list - not Node<T>
.
If you do that, instead of this
using (var linkedListEnumerator = myLinkedList.GetEnumerator())
{
while (linkedListEnumerator.MoveNext())
{
Console.WriteLine(linkedListEnumerator.Current.Data);
}
}
you would be able to do
foreach (var item in myLinkedList)
{
Console.WriteLine(item);
}
And besides that, by implementing IEnumerable<T>
, you'll be able to use LINQ extensions on the list. (see also VisualMelons comment).
Consider to implement this:
public bool Remove(T item)
{
// TODO: implement this
return <wasRemoved>;
}
You could try to implement the above and make a new post with an updated version with unit tests and we could then review that... :-)
Your use case should look as something like:
void RunLinkedList()
{
Console.WriteLine("Running the LinkedList class");
Console.WriteLine("----------------------------");
var myLinkedList = new LinkedList<int>();
myLinkedList.AddHead(99);
myLinkedList.AddHead(56);
myLinkedList.AddHead(23);
myLinkedList.AddHead(33);
myLinkedList.AddTail(8888);
myLinkedList.RemoveTail();
myLinkedList.RemoveHead();
Console.WriteLine("HEAD = " + myLinkedList.Head);
Console.WriteLine("TAIL = " + myLinkedList.Tail);
foreach (var item in myLinkedList)
{
Console.WriteLine(item);
}
}
$endgroup$
1
$begingroup$
With your suggestion,public T RemoveLast() {...}
, doesn't it violate Command-Query Separation? RemoveLast() modifies state. Is It okay to break the rule sometimes?
$endgroup$
– feature_creep
Mar 29 at 14:47
1
$begingroup$
+1; sadly (IMO) you can already useforeach
on the OP's class, but properly implementingIEnumerable<T>
will facilitate much more.
$endgroup$
– VisualMelon
Mar 29 at 14:56
$begingroup$
@VisualMelon: You're right. I know you can, but what I intended to show was that the Enumerator enumerates theT
's and not theNode<T>
s. By implementing IEnumerable<T> you'll be able to use the standard Linq extensions etc.
$endgroup$
– Henrik Hansen
Mar 29 at 15:08
$begingroup$
@feature_creep: IMO CQS is about not changing the object (the list) when querying it. Here I do the opposite: changing the object and provide the "change" to the client - it's not a query. It's a little different.
$endgroup$
– Henrik Hansen
Mar 29 at 15:12
add a comment |
$begingroup$
I've made the Node class public so I can use it for a binary tree implementation later
I don't think you can use this Node
type as a node in a binary tree, because nodes in binary trees typically has references to other nodes like Parent
, Left
and Right
. So IMO keep this Node
class as a dedicated node type for this linked list:
public class LinkedList<T>
{
class Node
{
public T Data { get; }
public Node Next { get; set; }
public Node Previous { get; set; }
public Node(T data)
{
Data = data;
}
}
In this way you can skip the type parameter on the Node
class. As shown above I've also made the Node
class immutable for the Data
property and hence no default constructor. It's easier to maintain, if you know that there is a one-to-one relationship between a data object and a Node
.
public Node<T> Head { get; private set; }
public Node<T> Tail { get; private set; }
It's fine to have a public Head
and Tail
property, but they should be of type T
and not Node
. The client should be agnostic about the inner implementation of your list and only "communicate" objects of type T
with it:
public T Head => _headNode.Data; // TODO check for null
public T Tail => _tailNode.Data; // TODO check for null
This will require that you have private nodes for head and tail as illustrated above.
public LinkedList(Node<T> node)
{
Head = node;
Tail = node;
}
Having a one and only constructor that takes a node (or item) is not a good idea, because you often want to instantiate an empty list and provide it as argument to a method or something like that. So your list should have a default constructor with no arguments:
public LinkedList()
{
}
You could also consider to have a constructor with a vector of items:
public LinkedList(IEnumerable<T> items)
{
foreach (var item in items)
{
AddTail(item);
}
}
public void AddToFirst(Node toAdd) {...}
public void AddToLast(Node toAdd) {...}
You would typically call these methods AddHead
and AddTail
:
public void AddHead(T item) {...}
public void AddTail(T item) {...}
as you would call RemoveFirst()
RemoveHead()
...
public void AddToFirst(Node<T> toAdd)
{
toAdd.Next = Head;
Head = toAdd;
}
public void AddToLast(Node<T> toAdd)
{
Tail.Next = toAdd; //OBS: This will fail if Tail is null!
Tail = toAdd;
}
Your Node<T>
class has a Previous
property, why don't you use that (doubly linked list)?
public void RemoveFirst()
{
Head = Head.Next;
}
This will fail, if Head
is null
.
public void RemoveLast()
{
var pointer = Head;
while (pointer.Next != Tail)
{
pointer = pointer.Next;
}
// pointer is now before Tail
Tail = pointer;
Tail.Next = null;
}
Why iterate through the entire list, when you have a reference to the last node in Tail
?:
public void RemoveLast()
{
if (Tail != null)
{
Tail = Tail.Previous;
Tail.Next = null;
}
}
You could consider to return the Data
value from the removed nodes.
public T RemoveLast() {...}
public IEnumerator<Node<T>> GetEnumerator()
{
var pointer = Head;
while (pointer != null)
{
yield return pointer;
pointer = pointer.Next;
}
}
It's fine to provide an enumerator. But it would be better to implement the IEnumerable<T>
interface instead - where T is the T
from your list - not Node<T>
.
If you do that, instead of this
using (var linkedListEnumerator = myLinkedList.GetEnumerator())
{
while (linkedListEnumerator.MoveNext())
{
Console.WriteLine(linkedListEnumerator.Current.Data);
}
}
you would be able to do
foreach (var item in myLinkedList)
{
Console.WriteLine(item);
}
And besides that, by implementing IEnumerable<T>
, you'll be able to use LINQ extensions on the list. (see also VisualMelons comment).
Consider to implement this:
public bool Remove(T item)
{
// TODO: implement this
return <wasRemoved>;
}
You could try to implement the above and make a new post with an updated version with unit tests and we could then review that... :-)
Your use case should look as something like:
void RunLinkedList()
{
Console.WriteLine("Running the LinkedList class");
Console.WriteLine("----------------------------");
var myLinkedList = new LinkedList<int>();
myLinkedList.AddHead(99);
myLinkedList.AddHead(56);
myLinkedList.AddHead(23);
myLinkedList.AddHead(33);
myLinkedList.AddTail(8888);
myLinkedList.RemoveTail();
myLinkedList.RemoveHead();
Console.WriteLine("HEAD = " + myLinkedList.Head);
Console.WriteLine("TAIL = " + myLinkedList.Tail);
foreach (var item in myLinkedList)
{
Console.WriteLine(item);
}
}
$endgroup$
I've made the Node class public so I can use it for a binary tree implementation later
I don't think you can use this Node
type as a node in a binary tree, because nodes in binary trees typically has references to other nodes like Parent
, Left
and Right
. So IMO keep this Node
class as a dedicated node type for this linked list:
public class LinkedList<T>
{
class Node
{
public T Data { get; }
public Node Next { get; set; }
public Node Previous { get; set; }
public Node(T data)
{
Data = data;
}
}
In this way you can skip the type parameter on the Node
class. As shown above I've also made the Node
class immutable for the Data
property and hence no default constructor. It's easier to maintain, if you know that there is a one-to-one relationship between a data object and a Node
.
public Node<T> Head { get; private set; }
public Node<T> Tail { get; private set; }
It's fine to have a public Head
and Tail
property, but they should be of type T
and not Node
. The client should be agnostic about the inner implementation of your list and only "communicate" objects of type T
with it:
public T Head => _headNode.Data; // TODO check for null
public T Tail => _tailNode.Data; // TODO check for null
This will require that you have private nodes for head and tail as illustrated above.
public LinkedList(Node<T> node)
{
Head = node;
Tail = node;
}
Having a one and only constructor that takes a node (or item) is not a good idea, because you often want to instantiate an empty list and provide it as argument to a method or something like that. So your list should have a default constructor with no arguments:
public LinkedList()
{
}
You could also consider to have a constructor with a vector of items:
public LinkedList(IEnumerable<T> items)
{
foreach (var item in items)
{
AddTail(item);
}
}
public void AddToFirst(Node toAdd) {...}
public void AddToLast(Node toAdd) {...}
You would typically call these methods AddHead
and AddTail
:
public void AddHead(T item) {...}
public void AddTail(T item) {...}
as you would call RemoveFirst()
RemoveHead()
...
public void AddToFirst(Node<T> toAdd)
{
toAdd.Next = Head;
Head = toAdd;
}
public void AddToLast(Node<T> toAdd)
{
Tail.Next = toAdd; //OBS: This will fail if Tail is null!
Tail = toAdd;
}
Your Node<T>
class has a Previous
property, why don't you use that (doubly linked list)?
public void RemoveFirst()
{
Head = Head.Next;
}
This will fail, if Head
is null
.
public void RemoveLast()
{
var pointer = Head;
while (pointer.Next != Tail)
{
pointer = pointer.Next;
}
// pointer is now before Tail
Tail = pointer;
Tail.Next = null;
}
Why iterate through the entire list, when you have a reference to the last node in Tail
?:
public void RemoveLast()
{
if (Tail != null)
{
Tail = Tail.Previous;
Tail.Next = null;
}
}
You could consider to return the Data
value from the removed nodes.
public T RemoveLast() {...}
public IEnumerator<Node<T>> GetEnumerator()
{
var pointer = Head;
while (pointer != null)
{
yield return pointer;
pointer = pointer.Next;
}
}
It's fine to provide an enumerator. But it would be better to implement the IEnumerable<T>
interface instead - where T is the T
from your list - not Node<T>
.
If you do that, instead of this
using (var linkedListEnumerator = myLinkedList.GetEnumerator())
{
while (linkedListEnumerator.MoveNext())
{
Console.WriteLine(linkedListEnumerator.Current.Data);
}
}
you would be able to do
foreach (var item in myLinkedList)
{
Console.WriteLine(item);
}
And besides that, by implementing IEnumerable<T>
, you'll be able to use LINQ extensions on the list. (see also VisualMelons comment).
Consider to implement this:
public bool Remove(T item)
{
// TODO: implement this
return <wasRemoved>;
}
You could try to implement the above and make a new post with an updated version with unit tests and we could then review that... :-)
Your use case should look as something like:
void RunLinkedList()
{
Console.WriteLine("Running the LinkedList class");
Console.WriteLine("----------------------------");
var myLinkedList = new LinkedList<int>();
myLinkedList.AddHead(99);
myLinkedList.AddHead(56);
myLinkedList.AddHead(23);
myLinkedList.AddHead(33);
myLinkedList.AddTail(8888);
myLinkedList.RemoveTail();
myLinkedList.RemoveHead();
Console.WriteLine("HEAD = " + myLinkedList.Head);
Console.WriteLine("TAIL = " + myLinkedList.Tail);
foreach (var item in myLinkedList)
{
Console.WriteLine(item);
}
}
edited Mar 29 at 15:29
answered Mar 29 at 11:47
Henrik HansenHenrik Hansen
8,30011231
8,30011231
1
$begingroup$
With your suggestion,public T RemoveLast() {...}
, doesn't it violate Command-Query Separation? RemoveLast() modifies state. Is It okay to break the rule sometimes?
$endgroup$
– feature_creep
Mar 29 at 14:47
1
$begingroup$
+1; sadly (IMO) you can already useforeach
on the OP's class, but properly implementingIEnumerable<T>
will facilitate much more.
$endgroup$
– VisualMelon
Mar 29 at 14:56
$begingroup$
@VisualMelon: You're right. I know you can, but what I intended to show was that the Enumerator enumerates theT
's and not theNode<T>
s. By implementing IEnumerable<T> you'll be able to use the standard Linq extensions etc.
$endgroup$
– Henrik Hansen
Mar 29 at 15:08
$begingroup$
@feature_creep: IMO CQS is about not changing the object (the list) when querying it. Here I do the opposite: changing the object and provide the "change" to the client - it's not a query. It's a little different.
$endgroup$
– Henrik Hansen
Mar 29 at 15:12
add a comment |
1
$begingroup$
With your suggestion,public T RemoveLast() {...}
, doesn't it violate Command-Query Separation? RemoveLast() modifies state. Is It okay to break the rule sometimes?
$endgroup$
– feature_creep
Mar 29 at 14:47
1
$begingroup$
+1; sadly (IMO) you can already useforeach
on the OP's class, but properly implementingIEnumerable<T>
will facilitate much more.
$endgroup$
– VisualMelon
Mar 29 at 14:56
$begingroup$
@VisualMelon: You're right. I know you can, but what I intended to show was that the Enumerator enumerates theT
's and not theNode<T>
s. By implementing IEnumerable<T> you'll be able to use the standard Linq extensions etc.
$endgroup$
– Henrik Hansen
Mar 29 at 15:08
$begingroup$
@feature_creep: IMO CQS is about not changing the object (the list) when querying it. Here I do the opposite: changing the object and provide the "change" to the client - it's not a query. It's a little different.
$endgroup$
– Henrik Hansen
Mar 29 at 15:12
1
1
$begingroup$
With your suggestion,
public T RemoveLast() {...}
, doesn't it violate Command-Query Separation? RemoveLast() modifies state. Is It okay to break the rule sometimes?$endgroup$
– feature_creep
Mar 29 at 14:47
$begingroup$
With your suggestion,
public T RemoveLast() {...}
, doesn't it violate Command-Query Separation? RemoveLast() modifies state. Is It okay to break the rule sometimes?$endgroup$
– feature_creep
Mar 29 at 14:47
1
1
$begingroup$
+1; sadly (IMO) you can already use
foreach
on the OP's class, but properly implementing IEnumerable<T>
will facilitate much more.$endgroup$
– VisualMelon
Mar 29 at 14:56
$begingroup$
+1; sadly (IMO) you can already use
foreach
on the OP's class, but properly implementing IEnumerable<T>
will facilitate much more.$endgroup$
– VisualMelon
Mar 29 at 14:56
$begingroup$
@VisualMelon: You're right. I know you can, but what I intended to show was that the Enumerator enumerates the
T
's and not the Node<T>
s. By implementing IEnumerable<T> you'll be able to use the standard Linq extensions etc.$endgroup$
– Henrik Hansen
Mar 29 at 15:08
$begingroup$
@VisualMelon: You're right. I know you can, but what I intended to show was that the Enumerator enumerates the
T
's and not the Node<T>
s. By implementing IEnumerable<T> you'll be able to use the standard Linq extensions etc.$endgroup$
– Henrik Hansen
Mar 29 at 15:08
$begingroup$
@feature_creep: IMO CQS is about not changing the object (the list) when querying it. Here I do the opposite: changing the object and provide the "change" to the client - it's not a query. It's a little different.
$endgroup$
– Henrik Hansen
Mar 29 at 15:12
$begingroup$
@feature_creep: IMO CQS is about not changing the object (the list) when querying it. Here I do the opposite: changing the object and provide the "change" to the client - it's not a query. It's a little different.
$endgroup$
– Henrik Hansen
Mar 29 at 15:12
add a comment |
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f216453%2flinked-list-implementation-along-with-unit-test%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown