For a school project I am making an RPN calculator. This calculator has an abstract class Stack where three different implementations of stacks derive from. One of them is a linked list stack. For these stacks I have to show what values are on the stack. To do this I use an array. For my arraystack and list stack it was easy, but I can't figure out how to convert a linked list to an array. What is the best way to do that?
This is the code that I use for my linked list.
public class Node
{
public int data;
public Node next;
public Node(int i)
{
data = i;
next = null;
}
public void Add(int i)
{
if (next == null)
{
next = new Node(i);
}
else
{
next.Add(i);
}
}
}
public class MyLinkedList
{
private Node headNode;
private int count;
public MyLinkedList()
{
headNode = null;
count = 0;
}
public int Count()
{
return count;
}
public void Add(int i)
{
if (headNode == null)
{
headNode = new Node(i);
}
else
{
headNode.Add(i);
}
count++;
}
Implement IEnumerable on your LinkedList
using System.Linq;
Call ToArray on the LinkedList.
Implementing IEnumerable is trivial. Simply start at the root node in your list, yield return Node.data;, and move to the next node. Rinse and repeat until the next node is null.
Add a new method to your class.
public class MyLinkedList
{
... keep existing methods here ...
public int[] ToArray() {
var result = new int[count]();
var index = 0;
var node = headnode;
while (node != null) {
result[index] = node.data;
node = node.next;
}
return result;
}
Eh... Something like that?
public class MyLinkedList {
...
public Node[] ToArray() {
// You´ve got pre-computed count - let´s use it
Node[] result = new Node[count];
Node node = headNode;
for (int i = 0; i < result.Length; ++i) {
result[i] = node;
node = node.next;
}
return result;
}
}
P.S. public fields like next in the Node class is a bad practice. Convert them into properties
As #Will suggested, I would implement IEnumerable<int> by your class. That will bring you to powerful world of LINQ where you will be able to convert your linked list to array, list, or just filter nodes:
public class MyLinkedList : IEnumerable<int>
{
// your code here
public IEnumerator<int> GetEnumerator()
{
Node current = headNode;
while(current != null)
{
yield return current.data;
current = current.next;
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Now you can use all LINQ extensions with your class:
MyLinkedList myList = new MyLinkedList();
myList.Add(10);
myList.Add(15);
myList.Add(20);
int[] array = myList.ToArray();
List<int> list = myList.ToList();
// items above 13
var items = myList.Where(i => i > 13);
Related
I am given this set of code and I need to fill it up with some code above the while loop and in the While loop. I have seen some documentation but all i have seen is search methods with two arguments and this one only has one. I already wrote the part inside the while loop but im note sure if that is correct. How can I finish this code so that it searches for the value given as the parameter?
note: this is not a homework assignment where I ask you to do it for me, rather this is one of the few resources we have for studying and if you could complete this it would give me a better grasp.
When I run this code now I get this error message:
Type "Tests.Node" does not contain a definition for "value" and no extension method "value" of type "Tests.Node" could be found. Are you missing an assembly reference?
{
public class Node<T> where T : IComparable
{
public T Value { get; }
public Node<T> Next { get; set; }
public Node(T value, Node<T> next)
{
this.Value = value;
this.Next = next;
}
}
public class LinkedList<T> where T : IComparable
{
public Node<T> start;
public LinkedList()
{
start = null;
}
public LinkedList(Node<T> node)
{
start = node;
}
public Node<T> Search(T value)
{
[here is code needed]
while (start != null)
if(start.value.CompareTo(value) == 0){
return start;
}
start = start.next;
}
}
public class Program {
public static void Main(string[] args){
var list =
new LinkedList<int>(
new Node<int>(
5, new Node<int>(
7, new Node<int>(
21, new Node<int>(
30, null)
)
)
)
);
var a = 21;
var fr = list.Search(a);
}
}
}
You are very close to correct solution. First of all you need to fix compiler errors - change value and next to Value and Next, cause that how properties on your Node class are called.
Next you need to add curly brackets so the while block will execute assignment start = start.Next; (currently only if statement is inside while, so you will end with infinite loop)
Next you need to fix return - add return null; after while block - value you will return if nothing is found (also without it code will not compile).
Lastly you will need to fix the issue with changing the list during search (you are modifying start field of your LinkedList class with start = start.Next, you should not do that), introduce a temporary variable (i've name it curr), assign it value of start and use it in your while loop:
public Node<T> Search(T value)
{
var curr = start;
while (curr != null)
{
if (curr.Value.CompareTo(value) == 0)
{
return curr;
}
curr = curr.Next;
}
return null;
}
I suggest implementing IEnumerable<Node<T>> interface
public class Node<T> : IEnumerable<Node<T>> where T : IComparable {
public IEnumerator<Node<T>> GetEnumerator() {
for (Node<T> item = this; item != null; item = item.Next)
yield return item;
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
...
Then you can use Linq to query the collection:
using System.Linq;
...
public static void Main(string[] args) {
LinkedList<int> list = ...
int a = 21;
var fr = list.start.FirstOrDefault(item => item.Value == a);
Lets say I have a list of items:
[a,b,b,a,c,d,a,d,b,c]
and I need to know, for each item, how many items along do I have to traverse till I get n unique items, (and return eg -1, or otherwise indicate if that's not possible)
So here, if n = 4, I would return
[6,5,4,6,5,5,4,-1,-1,-1]
since
a,b,b,a,c,d contains 4 unique elements
b,b,a,c,d contains 4 unique elements
b,a,c,d contains 4 unique elements,
a,c,d,a,d,b contains 4 unique elements
etc.
I used
List.Select((x,i) => {
var range = List.Skip(i).GroupBy(y => y).Take(n);
if (range.Count() == n)
return range.SelectMany(y => y).Count();
return -1;
});
Although i'm pretty sure this is horribly non-performant.
To try to minimize overhead, I created a ListSpan extension class for managing subparts of a List - something like ArraySegment for List, but (loosely) modeled on Span:
public class ListSpan<T> : IEnumerable<T>, IEnumerable {
List<T> baseList;
int start;
int len;
public ListSpan(List<T> src, int start = 0, int? len = null) {
baseList = src;
this.start = start;
this.len = len ?? (baseList.Count - start);
if (this.start + this.len > baseList.Count)
throw new ArgumentException("start+len > Count for ListSpan");
}
public T this[int n]
{
get
{
return baseList[start + n];
}
set
{
baseList[start + n] = value;
}
}
public class ListSpanEnumerator<Te> : IEnumerator<Te>, IEnumerator {
int pos;
List<Te> baseList;
int end;
Te cur = default(Te);
public ListSpanEnumerator(ListSpan<Te> src) {
pos = src.start - 1;
baseList = src.baseList;
end = src.start + src.len;
}
public Te Current => cur;
object IEnumerator.Current => Current;
public bool MoveNext() {
if (++pos < end) {
cur = baseList[pos];
return true;
}
else {
cur = default(Te);
return false;
}
}
public void Reset() => pos = 0;
public void Dispose() { }
}
public IEnumerator<T> GetEnumerator() => new ListSpanEnumerator<T>(this);
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
public static class ListExt {
public static ListSpan<T> Slice<T>(this List<T> src, int start = 0, int? len = null) => new ListSpan<T>(src, start, len);
}
Then I created an extension method to return the distance (in Take terms) required to get n unique items from an IEnumerable:
public static class IEnumerableExt {
public static int DistanceToUnique<T>(this IEnumerable<T> src, int n, IEqualityComparer<T> cmp = null) {
var hs = new HashSet<T>(cmp ?? EqualityComparer<T>.Default);
var pos = 0;
using (var e = src.GetEnumerator()) {
while (e.MoveNext()) {
++pos;
hs.Add(e.Current);
if (hs.Count == n)
return pos;
}
}
return -1;
}
}
Now the answer is relatively straight forward:
var ans = Enumerable.Range(0, src.Count).Select(p => src.Slice(p).DistanceToUnique(n));
Basically I go through each position in the original (src) List and compute the distance to n unique values from that position using a ListSpan of the List starting at that position.
This still isn't terribly efficient in that I am creating a HashSet for every element in the original List and putting all the following elements in it, and traversing the elements up to k! times for a k element List. Still trying to come up with something really efficient.
In C#, I am currently trying to link one node from a certain LinkedList to another node in another LinkedList. I am trying to make this for a game where tiles are connected in levels stacked on top of eachother. However, changing the Next property in the list gives an error. This is the code:
tileList2.First.Next = tileList1.First;
This is the error;
Property or indexer 'LinkedListNode.Next' cannot be assigned to -- it is read only."
How can I (otherwise) set the Next of this node to the First of the other node? What is causing this error? Is there any workaround?
Every node in the framework implementation of LinkedList has a reference to the list containing it, which makes transferring elements to another list O(n) instead of O(1), which defeats the purpose of the linked list implementation. If you want to transfer elements to another list in this implementation, you would have to remove and add them one by one (using Remove and AddAfter on the list) so that they each get a reference to the other list.
I suspect this is not what you're after, though. As other comments state, the needs of your list are probably simple enough that you'd be better off making your own much simpler linked list. And that question is already addressed elsewhere on SO (Creating a very simple linked list).
Since that answer doesn't include easy enumeration and initialization, I made my own.
class ListNode<T> : IEnumerable<T>
{
public T data;
public ListNode<T> Next;
private ListNode() { }
public ListNode(IEnumerable<T> init)
{
ListNode<T> current = null;
foreach(T elem in init)
{
if (current == null) current = this; else current = current.Next = new ListNode<T>();
current.data = elem;
}
}
class ListEnum : IEnumerator<T>
{
private ListNode<T> first;
private ListNode<T> current;
bool more;
public ListEnum(ListNode<T> first) { this.first = first; more = true; }
public T Current { get { return current.data; } }
public void Dispose(){}
object System.Collections.IEnumerator.Current { get { return current.data; } }
public void Reset() { current = null; more = true; }
public bool MoveNext()
{
if (!more)
return false;
else if (current == null)
return more = ((current = first) != null);
else
return more = ((current = current.Next) != null);
}
}
public IEnumerator<T> GetEnumerator()
{
return new ListEnum(this);
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
static void Main(string[] args)
{
ListNode<int> l1 = new ListNode<int>(new int[] {3,1,4,1,5,9});
ListNode<int> l2 = new ListNode<int>(new int[] { 5 });
l2.Next = l1.Next;
foreach (int i in l2)
Console.WriteLine(i);
}
you can't set LinkedListNode.Next directly, it is readonly.
you also can't use LinkedList.AddLast because the LinkedlListNode you are trying to add is already in a list.
you actually need to break the lists and create new ones.
or you could implement your own linked list.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Implementing C# IEnumerable<T> for a LinkedList class
After searching the web for some hours now I still can't understand how IEnumerable/IEnumerator works and how to implement it.
I've constructed a simple LinkedList from scratch but now I want to implement IEnumerable for it so I can foreach it. How do I do that?
class Program
{
LL myList = new LL();
static void Main()
{
var gogo = new Program();
}
public Program()
{
myList.Add("test");
myList.Add("test1");
foreach (var item in myList) //This doesn't work because I havn't implemented Ienumerable
Console.WriteLine(item);
Console.Read();
}
}
class LL
{
private LLNode first;
public void Add(string s)
{
if (this.first == null)
this.first = new LLNode() { Value = s };
else
{
var node = this.first;
while (node.Next != null)
node = node.Next;
node.Next = new LLNode() { Value = s };
}
}
class LLNode
{
public string Value { get; set; }
public LLNode Next { get; set; }
}
It's really not that hard. To implement IEnumerable you just need to implement the GetEnumerator method.
To do that you need to create another class that implements IEnumerator. Implementing IEnumerator is pretty easy. Generally you will pass a reference to your collection when you create the enumerator (in GetEnumerator) and the enumerator will keep track of which item is the current item. Then it will provide MoveNext which just changes the Current to the next item (and returns false if it's at the end of the list) and Reset which just sets the Current back to before the first node.
So in very broad, untested code terms, you need something like:
public class MyLinkedListEnumerator : IEnumerator
{
private LL myList;
private LLNode current;
public object Current
{
get { return current; }
}
public MyLinkedListEnumerator(LL myList)
{
this.myList = myList;
}
public bool MoveNext()
{
if (current == null) {
current = myList.first;
}
else {
current = current.Next;
}
return current != null;
}
public void Reset()
{
current = null;
}
}
What you need to do is:
(1) Make your class implement IEnumerable<T> where T is the type of the enumerated items. (In your case, it looks like it would be LLNode).
(2) Write a public IEnumerator<T> GetEnumerator. Implement it using the "yield" keyword.
(3) Add a IEnumerator IEnumerable.GetEnumerator() method and just return GetEnumerator().
The following code should make this clear. Where I have <int>, you should put <LLNode>, assuming that is the correct type.
using System;
using System.Collections;
using System.Collections.Generic;
namespace Demo
{
internal class Program
{
private static void Main()
{
var test = new MyDemo();
foreach (int item in test)
{
Console.WriteLine(item);
}
}
}
public class MyDemo: IEnumerable<int>
{
public IEnumerator<int> GetEnumerator()
{
// Your implementation of this method will iterate over your nodes
// and use "yield return" to return each one in turn.
for (int i = 10; i <= 20; ++i)
{
yield return i;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
I would have modified your code to do it properly, but the code you posted won't compile.
[EDIT]
Now you've updated your code, I can see that you want to enumerate the values. Here's the completed code:
using System;
using System.Collections;
using System.Collections.Generic;
namespace Demo
{
internal class Program
{
private LL myList = new LL();
private static void Main()
{
var gogo = new Program();
}
public Program()
{
myList.Add("test");
myList.Add("test1");
foreach (var item in myList) // This now works.
Console.WriteLine(item);
Console.Read();
}
}
internal class LL: IEnumerable<string>
{
private LLNode first;
public void Add(string s)
{
if (this.first == null)
this.first = new LLNode
{
Value = s
};
else
{
var node = this.first;
while (node.Next != null)
node = node.Next;
node.Next = new LLNode
{
Value = s
};
}
}
public IEnumerator<string> GetEnumerator()
{
for (var node = first; node != null; node = node.Next)
{
yield return node.Value;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
private class LLNode
{
public string Value { get; set; }
public LLNode Next { get; set; }
}
}
}
I have to implement a call graph for expressions like Id = Id(Param); and that wasn't a problem.
Now I have to implement an enumerator which lists one at a time all topological orderings among the calls that satisfy the order of dependencies.
And here's the trouble.
This is a simple node for the call graph:
class CallGraphNode
{
private string name;
public List<CallGraphNode> dependents = new List<CallGraphNode>();
public int dependencies;
private bool executed = false;
public bool Executable { get { return dependencies == 0; } }
public bool Executed { get { return executed; } set { executed = value; } }
public CallGraphNode(string name)
{
this.name = name;
dependencies = 0;
}
public override string ToString()
{
return name;
}
public void AddDependent(CallGraphNode n)
{
dependents.Add(n);
}
}
And this is the call graph class itself:
class CallGraph : IEnumerable<List<CallGraphNode>>
{
public List<CallGraphNode> nodes = new List<CallGraphNode>();
public void AddNode(CallGraphNode n)
{
nodes.Add(n);
}
public static void Show(IEnumerable<CallGraphNode> n)
{
foreach (CallGraphNode node in n)
{
Console.Write("{0} ", node);
}
Console.WriteLine();
}
static IEnumerable<List<CallGraphNode>> EnumerateFunctions(List<CallGraphNode> executable, List<CallGraphNode> res)
{
if (executable.Count == 0)
yield return res;
else foreach (CallGraphNode n in executable)
{
if (!n.Executed)
res.Add(n);
List<CallGraphNode> next_executable = new List<CallGraphNode>(executable);
executable.Remove(n);
foreach (CallGraphNode m in n.dependents)
if (--m.dependencies == 0)
next_executable.Add(m);
foreach (List<CallGraphNode> others in EnumerateFunctions(next_executable, res))
yield return others;
foreach (CallGraphNode m in n.dependents)
m.dependencies++;
if (!n.Executed)
res.Remove(n);
}
}
IEnumerator<List<CallGraphNode>> IEnumerable<List<CallGraphNode>>.GetEnumerator()
{
List<CallGraphNode> executable = new List<CallGraphNode>();
foreach (CallGraphNode n in nodes)
if (n.Executable || n.Executed)
executable.Add(n);
List<CallGraphNode> output = new List<CallGraphNode>();
foreach (List<CallGraphNode> list in EnumerateFunctions(executable, output))
yield return list;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{ throw new NotImplementedException(); }
}
Now, the problem is it just won't work. When I try to create an IEnumerator and assign it the GetEnumerator() return value, I get a casting error and that's honestly what I expected when trying to do so:
IEnumerator<List<CallGraphNode>> lt = cg.GetEnumerator();
Then I've tried:
System.Collections.Generic.List<CallGraphNode>.Enumerator en = cg.nodes.GetEnumerator();
This works, but the method EnumerateFunctions is never called and the enumerator just contains the original list of graph nodes.
Any ideas?
The problem is that you're implementing both IEnumerable<T> and IEnumerable using explicit interface implementation.
You probably want to change this declaration:
IEnumerator<List<CallGraphNode>> IEnumerable<List<CallGraphNode>>.GetEnumerator()
to be a "normal" interface implementation:
public IEnumerator<List<CallGraphNode>> GetEnumerator()
Alternatively, you could stick with explicit interface implementation, but use:
IEnumerable<List<CallGraphNode>> sequence = cg;
IEnumerator<List<CallGraphNode>> lt = sequence.GetEnumerator();