C# ArrayList.Add() overwriting previous objects on add - c#

I have written a simple method that receives a Generic that I wish to place into an ArrayList using the ArrayList.Add() method. However I have discovered that when I go add a new item with the same type as previous items in the ArrayList this new item overwrites the previous items individual properties.
Here's the code its pretty basic and rather embarrassingly I can't seem to rectify this overwriting problem.
public class ChromosomeTree<T>
{
private GeneNode<T> root;
private ArrayList children = new ArrayList();
private int depMax;
string stemp;
public ChromosomeTree()
{
root = null;
}
public virtual void Clear()
{
root = null;
}
public GeneNode<T> Root
{
get
{
return root;
}
set
{
root = value;
}
}
public int MaxDepth
{
get
{
return depMax;
}
set
{
depMax = value;
}
}
public ArrayList Children
{
get
{
return children;
}
}
public GeneNode<T> lastChild()
{
return (GeneNode<T>)this.Children[this.Children.Count - 1];
}
public void addFull(GeneNode<T> node)
{
//check if the chromosome tree has a root if not add the first node as the chromosomes root
if (this.Root == null)
{
this.Root = node;
children.Add(node);
stemp += " " + node.Value;
}
else
{
for (int i = 0; i <= this.Children.Count - 1; i++)
{
GeneNode<T> parent = (GeneNode<T>)this.Children[i];
//check to ensure maxDepth of chromosome tree is not exceeded
if (parent.Depth != this.MaxDepth)
{
//check to see if the current node stil has room for another node to be added to it
if ((parent.Children == null) || (parent.Children[1] == null))
{
children.Add(node);
parent.Add(node);
stemp += " " + node.Value;
break;
}
}
else
{
break;
}
}
}
}
public override string ToString()
{
string chromosome = String.Empty;
foreach(GeneNode<Gene> gene in this.Children)
{
chromosome += " " + gene.Value.GeneValue.ToString();
}
return chromosome;
}
}
Im pretty sure its a simple mistake but ive looked at this for so long I cant see the wood from the trees. Any thoughts would be greatly appreciated.
Many thanks in advance.
Luke
here is the code that utilises the this class.
EDIT : THE OVERWRITE HAPPENS WHEN THE METHOD IS CALLED NOT AFTER THE METHOD HAS EXECUTED ITS LOGIC
class SimpleChromosome
{
Random rand = new Random();
Gene funcGene = new Gene();
Gene termGene = new Gene();
private string sChromosome;
private int currentdepth;
private string grownChromosome()
{
return sChromosome;
}
public ChromosomeTree<Gene> fullChromosome()
{
ChromosomeTree<Gene> chromosone = new ChromosomeTree<Gene>();
//chromosone.MaxDepth = rand.Next(1, 5);
chromosone.MaxDepth = 1;
int maxGenes = (int)Math.Pow(2, chromosone.MaxDepth + 1) - 1;
for (int i = 0; i <= chromosone.MaxDepth; i++)
{
int numNodesForLevel = (int)Math.Pow(2, i);
int numNodesOnLevel = 0;
for (int j = 0; j < numNodesForLevel; j++)
{
if (currentdepth != chromosone.MaxDepth)
{
funcGene.GenerateValue(GeneType.Function);
GeneNode<Gene> geneNode = new GeneNode<Gene>(funcGene);
sChromosome += " " + geneNode.Value;
chromosone.addFull(geneNode);
numNodesOnLevel++;
}
else
{
termGene.GenerateValue(GeneType.Terminal);
GeneNode<Gene> geneNode = new GeneNode<Gene>(termGene);
sChromosome += " " + geneNode.Value;
chromosone.addFull(geneNode);
numNodesOnLevel++;
}
if ((numNodesForLevel == numNodesOnLevel) && (currentdepth != chromosone.MaxDepth))
{
currentdepth++;
}
}
}
currentdepth = 0;
//Console.WriteLine("Before ADD :" + sChromosome);
sChromosome = "";
return chromosone;
}
}

Post the code where you are adding a new object of this type to your ArrayList.
My guess is that you are using two references to the same object.
Remember that objects are reference types, therefore if you assign them to each other you are only assigning their references. e.g. in the following code:
Foo foo1 = new Foo();
foo1.x = 1;
Foo foo2 = new Foo();
foo2.x = 2;
foo2 = foo1; // foo2 now points to the same object as foo1;
// foo1.x does not get copied into foo2.x.
// You have also lost your reference to the original foo2 object here and it will be garbage collected.
foo2.x = 100;
// since foo2 and foo1 are now pointing to the same object. both foo2.x and foo1.x will be 100

For this sort of relationship you really should be coding to interfaces. eg.
public interface IGeneNode{
//genenode definition including perhaps equality interfaces etc
}
If the above is correct then you can overload your Assignment operator to pass the values you wish to pass.
This might be useful to you as well.
C# - Multiple generic types in one list

in this loop parent == Children[i] and Children is a getter for children
Do you really mean to be adding the same node to children and parent, which would make the same node a sibling of parent in addition to a child? I'm not clear on what you're really trying to do but this seems wrong:
if ((parent.Children == null) || (parent.Children[1] == null))
{
children.Add(node);
parent.Add(node);
..
}
edit
From the supporting code you posted the problem could be related to how you create objects:
/* outside the loop */
Gene funcGene = new Gene();
Gene termGene = new Gene();
...
/* inside the loop*/
funcGene.GenerateValue(GeneType.Function);
GeneNode<Gene> geneNode = new GeneNode<Gene>(funcGene);
sChromosome += " " + geneNode.Value;
chromosone.addFull(geneNode);
Seems like you are create a new GeneNode multiple times using a one of two instances of Gene in its constructor. Assuming that your GeneNode is saving that as a property value, each GeneNode is going to reference the same instance of Gene (well, one of two, either funcGene or termGene). I'm guessing this is what you mean when you say new item with the same type as previous items in the ArrayList this new item overwrites the previous items individual properties. Any changes to a Gene property assigned from the constructor in any node of the same type will refer to the same Gene. Even though you are creating new GeneNodes they are constructed from the same Gene.
So assuming that GeneNode.Value references the Gene that it was constructed with, there can only be two different values returned (corresponding to the the current value of one of the two Gene instances) by any node at any given point in time.
Probably, you want to move the code to create a new Gene inside your loop.

Related

Remove the biggest value from a linked list

So I've said it in the title, I want to delete the biggest value from a LinkedList, can't get my head around how to exactly do it. I tried this but I get an error.
//Remove n from list 'first'
public static void Remove(Node<int> first, Node<int> n)
{
Node<int> pos = first;
while (pos.GetNext() != n)
pos = pos.GetNext();
pos.SetNext(n.GetNext());
}
public static void DeleteMaxValue(Node<int> first)
{
int max = 0;
Node<int> pos = first;
Node<int> maxNode = null;
while(pos.GetNext() != null)
{
if (pos.GetNext().GetValue() > max)
{
maxNode = new Node<int>(pos.GetNext().GetValue());
}
pos = pos.GetNext();
}
Remove(first, maxNode);
}
imagine this is your Node structure in linked list
public class Node
{
public int data;
public Node next;
}
you can use this function to find the biggest number in the linked list and then remove it.
public int GetMax(Node head)
{
int max = int.MinValue();
while(head != null)
{
if(max < head.data)
max = head.data;
head = head.next;
}
return max;
}
Several issues:
max is never updated. It should be updated when you have found a greater value, otherwise the last positive value is considered the greatest.
maxNode is never a node that is in the list, since it is created as a new node. By consequence the Remove function will not find it and nothing gets deleted.
Your function's signature has no way of deleting the first node, since first is passed by value. There is no way to solve this for all cases, unless you change the design:
Either let first be a member of your class, and then don't pass it as argument, or
Let the function return the (potentially) new value of first, so the caller can adapt its own reference to the head of the list.
max = 0 assumes that your list cannot have negative values. In case this is possible, I would suggest initialising max with the value that is in the first node (after having checked that the list is not empty).
Instead of cycling again through the list with Remove, keep a reference to the node the precedes the node that is to be deleted.
Here is a function that returns the value of first, so the caller can make an update to their own reference in case the first node was deleted:
// Return type changed: the function will return the first node
public static Node<int> DeleteMaxValue(Node<int> first)
{
if (first == null) { // In an empty list there is nothing to delete
return;
}
int max = first.GetValue(); // Don't use 0, values might be negative
Node<int> pos = first;
Node<int> maxNode = first;
Node<int> beforeMaxNode = null; // Have a reference that lags behind
while(pos.GetNext() != null)
{
int val = pos.GetNext().GetValue();
if (val > max)
{
max = val; // Update max
beforeMaxNode = pos; // Don't create a new node
}
pos = pos.GetNext();
}
if (beforeMaxNode == null) { // First node has the maximum
// Now `first` reference will change, so it's important to return
// that new reference, else the caller will not see any change
first = maxNode.GetNext();
} else {
beforeMaxNode.SetNext(maxNode.GetNext());
}
return first;
}

swapping nodes in doubly linked list

Trying to swap the second and third nodes from a doubly linked list in c# with the following method:-
public static void swapNodes(List dblLinkList)
{
Node tempnodeTwo = dblLinkList.firstNode.next; //node two in list
Node tempnodeThree = dblLinkList.firstNode.next.next; //node three in list
Node tempnodeFive = tempnodeTwo.previous;
Node tempnodeSix = tempnodeThree.next;
tempnodeThree.previous = tempnodeFive;
tempnodeThree.next = tempnodeThree;
tempnodeTwo.previous = tempnodeTwo;
tempnodeTwo.next = tempnodeSix;
}
The following shows the output: The first is the original list and the second is the result of the method.
N:19:16 19:16:9 16:9:15 9:15:15 15:15:N
N:19:16 16:16:15 9:15:15 15:15:N
Where am I going wrong?? I have already studied previous questions about this topic which gave me the idea for the code but now stuck!
It seems that you assume tempnodeThree is the third and tempnodeTwo is the second node
of the linked list regardless of the changes you make but this is not the case.
After the initializations what you get is:
tempnodeFive <--> tempnodeTwo <--> tempnodeThree <--> tempnodeSix
And you need is:
tempnodeFive <--> tempnodeThree <--> tempnodeTwo <--> tempnodeSix
So what you have to change from left to right are:
tempNodeFive.next, tempNodeTwo.previous, tempNodeTwo.next, tempNodeThree.previous, tempNodeThree.next, tempNodeSix.previous
Let's go over them following the 2nd linked list representation:
tempNodeFive.next = tempNodeThree;
tempNodeTwo.previous = tempnodeThree;
tempNodeTwo.next = tempnodeSix;
tempNodeThree.previous = tempnodeFive;
tempNodeThree.next = tempnodeTwo;
tempNodeSix.previous = tempnodeTwo;
These six lines are what you need.
PS: You can reconsider variable names for a readable and maintainable code, esp. tempNodeFive and tempnodeSix because five and six does not make any sense as an index and it arises confusion while reading the code.
well here in these lines
tempnodeThree.next = tempnodeThree;
tempnodeTwo.previous = tempnodeTwo;
you are setting the next of a node to itself and the previous of another to itself.
don't you mean
tempnodeThree.next = tempnodeTwo;
tempnodeTwo.previous = tempnodeThree;
I think you would have an easier time if you used better names.
I also would not implement this function like this -- I'd make the function suit it's name like this:
public static void swapNodes(Node a, Node b)
{
if (a == null) return;
if (b == null) return;
Node afterA = a.next;
Node beforeA = a.previous;
a.previous = b.previous;
if (b.previous != null) b.previous.next = a;
a.next = b.next;
if (b.next != null) b.next.previous = a;
b.next = afterA;
if (afterA != null) afterA.previous = b;
b.previous = beforeA;
if (beforeA != null) beforeA.next = b;
}
// call it like this
swapNodes(dblLinkList.firstNode.next, dblLinkList.firstNode.next.next);
Are you sure it's c#? Looks like java. C# has LinkedListNode<T> class, not Node. And LinkedListNode<T> has Next and Previous properties. With capitals. And they are read only.
Any way c# implementation looks like this:
using System;
using System.Collections.Generic;
namespace LinkedListSwap
{
class Program
{
static void Main(string[] args)
{
var list = new LinkedList<string>(new[] { "1st", "2nd", "3rd", "4th", "5th", "6th", "7th" });
Console.WriteLine(list.ToDisplayString());
list.Swap(2, 3);
Console.WriteLine(list.ToDisplayString());
}
}
static class LinkedListExtensions
{
public static void Swap<T>(this LinkedList<T> list, int firstIndex, int secondIndex)
{
if (firstIndex < 1 || firstIndex > list.Count)
throw new IndexOutOfRangeException($"Index out of range: {nameof(firstIndex)}");
if (secondIndex < 1 || secondIndex > list.Count)
throw new IndexOutOfRangeException($"Index out of range: {nameof(secondIndex)}");
if (firstIndex == secondIndex)
return;
if (firstIndex > secondIndex)
(firstIndex, secondIndex) = (secondIndex, firstIndex);
int i = 0;
var leftNode = list.First;
while (++i < firstIndex)
leftNode = leftNode.Next;
var rightNode = leftNode.Next;
while (++i < secondIndex)
rightNode = rightNode.Next;
list.Replace(leftNode, rightNode);
list.Replace(rightNode, leftNode);
}
public static void Replace<T>(this LinkedList<T> list, LinkedListNode<T> oldNode, LinkedListNode<T> newNode)
{
list.AddAfter(oldNode, new LinkedListNode<T>(newNode.Value));
list.Remove(oldNode);
}
public static string ToDisplayString<T>(this LinkedList<T> list) => string.Join(" ", list);
}
}
Output is:
1st 2nd 3rd 4th 5th 6th 7th
1st 3rd 2nd 4th 5th 6th 7th

Objects in list get removed when applying Dijkstra's Algorithm implementation

I didn't know how to formulate the question title any better without getting too descriptive, I'm sorry in advance...
Anyhow, my problem is the following.
I have a List NodeList, and a secondary List named Unvisited.
I use the Method GetPath on the Unvisited list (it's an implementation of Dijkstra's Pathfidning Algorithm). But for some weird reason when I draw the texture stored in the Nodes in the NodeList some of the nodes (particularly, the nodes used to trace a path between) get removed.
I am looking for an explanation why the Nodes get removed from the NodeList even when I clearly set Unvisited equal NodeList...
EDIT: If there is any code that is missing to understand the problem, ask and I will edit!
Relevant Code:
public class Hotel
{
public List<Node> nodeList;
//constructor loadscontent and initialises list, ommitted here.
public void BuildHotel(ContentManager content)
{
for (int i = 0; i < 5; i++)
{
GuestRoom temp = new GuestRoom(100 + i, content, new Point(64 + (i * 64), 128), new Point(2, 1));
nodeList.Add(new Node(temp, new Point(64 + (i * 64), 128)));
}
// add edges between some nodes
for (int i = 0; i < 4; i++)
{
AddEdge(nodeList[i].Room.RoomId, nodeList[i + 1].Room.RoomId, 2);
}
guest = new Guest(content);
guest.Setpath(100, 104, nodeList);
}
}
class PathFinding
{
public List<Node> Unvisited;
public List<Node> Visited;
private Stack<Node> _temp = new Stack<Node>();
public Stack<Node> GetPath(int startroom, int finalroom, List<Node> nodeList)
{
Unvisited = nodeList;
Node startNode = Unvisited.DefaultIfEmpty(null).FirstOrDefault(x => x.Room.RoomId == startroom);
Node finalNode = Unvisited.DefaultIfEmpty(null).FirstOrDefault(x => x.Room.RoomId == finalroom);
if (startNode == null || finalNode == null)
{
Console.WriteLine("At least one of the nodes does not exist");
return null;
}
startNode.Distance = 0;
Node currentNode = startNode;
while (!IsVisited(currentNode, finalNode))
{
currentNode = Unvisited.Aggregate((l, r) => l.Distance < r.Distance ? l : r);
}
//reverse nodes in queue
Queue<Node> reversedqueue = MakePath(startNode, currentNode, finalNode);
for (int i = 0; i < MakePath(startNode, currentNode, finalNode).Count; i++)
{
_temp.Push(reversedqueue.Dequeue());
}
return _temp;
}
}
public class SimulationScreen : Screen
{
private Hotel hotel;
//.. other methods ommited.
public override void Activate(bool instancePreserved)
{
if (!instancePreserved)
{
if (_content == null)
_content = new ContentManager(ScreenManager.Game.Services, "Content");
ScreenManager.Game.ResetElapsedTime();
}
hotel = new Hotel(_content);
}
}
Visual Representation on the bug
Without the pathfinder turned on
Your problem is right here:
Unvisited = nodeList;
That's the problem, I have looked through my entire solution and there is not a single place where the nodes get removed from the NodeList ._. any removal from the list is from the Unvisited list... :s
After that assignment, any removal from the Unvisited list removes from the nodeList. List is a reference type, so when you change its value with an assignment you're really changing which object it refers to. Unvisited and nodeList both refer to the same object after this. To avoid this, instantiate a new List using the old one rather than assigning both lists to the same reference:
Unvisited = new List<Node>(nodeList);

How do i use class array so that it does not rewrite the first array that is stored?

Umm, i'm creating some subscription form and the max is 5 subscriptions.
So, i have a class Member and in the class i'm using the Get&Set method thingy(i've finally sorta learnt this get&set thing haha &i hope i'm using it correctly).
private string name;
private string address;
public string Name { get { return name; } set { name = value; } }
public string Address { get { return address; } set { address = value; } }
In the class form
Member[] memberArray = new Member[5];
Member memberSub = new Member();
BtnAdd_Click
memberSub.Name = TbName.Text;
memberSub.Address = TbAddress.Text;
for (int i = 0; i < memberArray.Length; i++)
{
if (memberArray[i] == null)
{
memberArray[i] = memberSub;
MessageBox.Show(TbName.Text + " has been added as a subscriber.");
break;
}
}
When i click display, it'll show the last input, and the front inputs are lost, idk why it's happening and there is an error? i think it's cause of the null array data, but i'm not sure.
Unless there is something wrong with my display button codes..?
for (int i = 0; i < memberArray.Length; i++)
{
rtbDisplay.Text += "Name: " + memberArray[i].Name + Environment.NewLine
+ "Address: " + memberArray[i].Address + Environment.NewLine
"----------------------------------------------------"
+ Environment.NewLine;
}
you are changing one object state and passing it to all of the array items,so at last you will only have the last entered input in all array item because they are all referring to single object memberSub and other array items also have memberSub reference so they will display same result,you need to instantiate each object of array separate and then set their properties like this:
for (int i = 0; i < memberArray.Length; i++)
{
if (memberArray[i] == null)
{
memberArray[i] = new Member();
memberArray[i].Name = TbName.Text;
memberArray[i].Address = TbAddress.Text;
MessageBox.Show(TbName.Text + " has been added as a subscriber.");
break;
}
}
You are only using one Member instance, so you will end up with an array full of references to the same instance. When you assign the object to the array, it's just the reference that is stored, it doesn't create a copy of the object to store in the array.
Instead of using a single Member instance, create a new instance each time that you want to store it in the array.
Just declare a reference for the object:
Member memberSub;
Then when you need to use one, create a new one:
memberSub = new Member();
memberSub.Name = TbName.Text;
memberSub.Address = TbAddress.Text;
You can consider using a list instead of an array:
List<Member> memberList = new List<Member>(5);
It's easier to add items to a list. You just have to keep track of the length of the list. Something like:
if (memberList.Count < 5) {
memberList.Add(memberSub);
} else {
MessageBox.Show("No more members allowed.");
}
When you display the members, just loop through all the items in the list. As there are no empty items in the list you don't need to skip any items. You can access the items in the list just as you access the items in an array. The only change is that the size of the list is in the Count property where you use Length for the array:
for (int i = 0; i < memberArray.Count; i++) {
...

Creating custom LinkedList

I am working on creating my own LinkedList. But I can't seem to solve this error. Can anyone help me!
The problem is that I want to insert an object after a particular element. I have created Find method to search for that particular item and return its reference, but I can't seem to solve it.
CustomLinkedList c = new CustomLinkedList();
c.Add(31);
c.Add(45);
c.Add(23);
c.Add(36);
c.PrintList();
Console.WriteLine("\n" + " Process of adding item at a spectifed location");
c.Addafter(66,23);
c.PrintList();
class Node
{
public object Element;
public Node Link;
public Node()
{
Element = null;
Link = null;
}
public Node(object TheElement)
{
Element = TheElement;
Link = null;
}
class CustomLinkedList
{
protected Node header;
protected Node last;
public CustomLinkedList()
{
//header = new Node("header");
}
private Node Find(object Item)
{
Node Current = new Node();
Current = header;
while (Current.Element != Item && Current.Link !=null)
{
Current = Current.Link;
}
return Current;
}
public void PrintList()
{
Node n = new Node();
n = header;
while (n != null)
{
Console.WriteLine(n.Element);
n = n.Link;
}
}
public void Add(object a)
{
Node n = new Node();
n.Element = a;
n.Link = null;
if (last == null)
{
header = n;
last = n;
}
else
{
last.Link = n;
last = n;
}
}
public void Addafter(object newitem, object After)
{
Node current = new Node();
Node newNode = new Node(newitem);
current = Find(After);
newNode.Link = current.Link;
current.Link = newNode;
}
}
The reason why it doesn't work is on this line:
while (Current.Element != Item && Current.Link !=null)
The == and != operators for the object type check for reference equality. If you're using your list with a value type (int for instance), the values will be boxed to distinct objects, and the != operator will always return true (see this article for details about boxing).
Consider this:
object x = 42;
object y = 42;
Console.WriteLine(x == y); // prints False
Console.WriteLine(x.Equals(y)); // prints True
Your current code is working fine with reference types:
var list = new CustomLinkedList();
list.Add("hello");
list.Add("!");
list.Addafter("world", "hello");
list.PrintList();
Output:
hello
world
!
But for value types it never finds the "after" value, so it appends the new item to the end of the list:
var list = new CustomLinkedList();
list.Add(1);
list.Add(3);
list.Addafter(2, 1);
list.PrintList();
Output:
1
3
2
So you need to replace the == operator with a call to Equals:
while (!object.Equals(Current.Element, Item) && Current.Link !=null)
I don't know what you're using for testing but value types won't work the way you think it should because the box values are being compared.
For example this will always return 3 (last element in list)
CustomLinkedList cList= new CustomLinkedList();
cList.Add(1);
cList.Add(2);
cList.Add(3);
Console.WriteLine(cList.Find(2).Element);
but this will work (output 2)
CustomLinkedList cll = new CustomLinkedList();
object a = 1;
object b = 2;
object c = 3;
cll.Add(a);
cll.Add(b);
cll.Add(c);
Console.WriteLine(cll.Find(b).Element);
The same goes for reference types that don't implement the != operators. So strings will work but little else will
Your code has 2 problems
The Find() function is returning the Tail element when the Item is not in the List.
Comparing n.Element and Item is tricky when they are of type object. Make your classes generic to solve that.
...
class CustomLinkedList<T> where T : IEquatable
{
....
private Node Find(object Item)
{
Node Current = header; // null for empty list
//while (Current.Element != Item && Current.Link !=null)
while(Current != null)
{
if (Current.Equals(Item) ) // can't always use ==
break;
Current = Current.Link;
}
return Current;
}
}

Categories