How to make a copy of an instance? [duplicate] - c#

This question already has answers here:
Cloning queue in c#
(2 answers)
Closed 2 years ago.
In this following code, what I want to do is to add a new value to my queue and then calculate the average of my current queue. But I don't want to just perform the calculation directly on my current queue itself. Instead I want to first copy the content of the current queue to a new queue and perform the calculation on the new queue. But I know that since classes are reference variables, so if I perform change anything within the new queue, the original one will change along. So how do I make a copy of the original queue and make changes on it without changing the original one?
public class MovingAverage {
public int size;
public Queue<int> que = new Queue<int>();
public Queue<int> copy = new Queue<int>();
/** Initialize your data structure here. */
public MovingAverage(int size)
{
this.size = size;
}
public double Next(int val)
{
if (que.Count == size) que.Dequeue();
que.Enqueue(val);
copy = que;
double sum = 0;
while(copy.Count != 0){
sum = sum + copy.Dequeue();
}
return sum / que.Count;
}
}

To make a copy of a Queue you can pass an enumerable collection to the constructor of a new instance
var newQueue = new Queue<int>(existingQueue);
As your Queue contents are ints (not reference types) they will not be connected to the original elements but beware, if you did this with a Queue full of class of eg Person, that each Queue instance would reference the same Persons and changing eg the Name property of the head Person would mean that each Queue sees the change
var q1 = new Queue<Person>( new [] { new Person() { Name = "Joe" } } );
var q2 = new Queue<Person>(q1);
q1.Peek().Name = "Jane";
Console.WriteLine(q2.Peek().Name); //prints Jane
//in essence, in memory, you have this:
q1 --head--> Person{ Name = "Joe" }
q2 --head----^
Two queue instances, but both of them have a reference to the same Person;
If you alter something about the Person, such as their Name, both Queues see it
You are free to change something about the Queue itself, as they are different instances:
var q1 = new Queue<Person>( new[] { new Person() { Name = "Joe" }, new Person() { Name = "Jane" } } );
var q2 = new Queue<Person>(q1); //both queues have two people in
Console.WriteLine(q1.Peek().Name); //Joe
Console.WriteLine(q2.Peek().Name); //Also Joe
q1.Dequeue(); //bye bye Joe
Console.WriteLine(q1.Peek().Name); //Jane
Console.WriteLine(q2.Peek().Name); //Joe
But the different queues point to the same Persons so you cannot mutate the Person objects independently. To do that, you'll have to clone/make anew the Person objects too, perhaps like:
var q2 = new Queue<Person>(q1.Select(p => new Person { Name = p.Name }));

Related

How to chain Objects in C#

I have got 4 questions:
How is it possible that I am able to print Console.WriteLine(list.head.Next.Next.Data).
From the AddHead(), the new object will save over the previous object n.Next?
I created a custom class to try and understand if I the above example is only List specific.
So, how is it possible that I can Console.WriteLine(cc.head.Next.Next.Next.Data) ?
How do I post code inside a box for the forum, this is my first post, please forgive me.
Thank you !
using System;
namespace GenericInterfaces
{
class Program
{
static void Main()
{
//Declare and instantiate a new generic SortedList class.
//Person is the type argument.
SortedList<Person> list = new SortedList<Person>();
//Create name and age values to initialize Person objects.
string[] names = new string[]
{
"Franscoise",
"Bill",
"Li",
"Sandra",
"Gunnar",
"Alok",
"Hiroyuki",
"Maria",
"Alessandro",
"Raul"
};
int[] ages = new int[] { 45, 19, 28, 23, 18, 9, 108, 72, 30, 35 };
//Populate the list with new Node Objects
for (int x = 0; x < 10; x++)
{
//ages[x] is integer
list.AddHead(new Person(names[x],ages[x]));
}
//Print out unsorted list.
foreach (var p in list)
{
System.Console.Write(p.ToString() + " ");
Console.WriteLine("Unsorted Data");
Console.WriteLine(list.head.Data);
Console.WriteLine(list.head.Next.Data);
Console.WriteLine(list.head.Next.Next.Data);
Console.WriteLine(list.head.Next.Next.Next.Data);
}
System.Console.WriteLine("Done with unsorted list");
Console.WriteLine("My Custom Class Experiment");
MyCustomClass cc = new MyCustomClass();
for (int i = 0; i < ages.Length; i++)
{
cc.AddHead(ages[i]);
}
Console.WriteLine("Added ages to custom class");
Console.WriteLine(cc.head.Data);
Console.WriteLine(cc.head.Next.Data);
Console.WriteLine(cc.head.Next.Next.Data);
Console.WriteLine(cc.head.Next.Next.Next.Data);
Console.WriteLine(cc.head.Next.Next.Next.Next.Data);
Console.WriteLine(cc.n.Data);
Console.WriteLine(cc.n.Next.Data);
}
}
//Type parameter T in angle brackets.
public class GenericList<T> : System.Collections.Generic.IEnumerable<T>
{
public Node head;
public Node current = null;
// Nested class is also generic on T
public class Node
{
public Node Next { get; set; } = null;
public T Data { get; set; }
public Node(T t) //T used in non-generic constructor
{
Data = t;
}
}
public GenericList() //constructor
{
head = null;
}
public void AddHead(T t) //T as method parameter type
{
Node n = new Node(t);
n.Next = head;
head = n;
}
// Implementation of the iterator
public System.Collections.Generic.IEnumerator<T> GetEnumerator()
{
Node current = head;
while (current != null)
{
yield return current.Data;
current = current.Next;
}
}
// IEnumerable<T> inherits from IEnumerable, therefore this class
// must implement both the generic and non-generic versions of
// GetEnumerator. In most cases, the non-generic method can
// simply call the generic method.
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public class MyCustomClass
{
public Mode head;
public Mode current = null;
public Mode n;
// Nested class is also generic on T
public class Mode
{
//public Mode Next { get; set; } = null;
public Mode Next;
public int Data { get; set; }
public Mode(int t) //T used in non-generic constructor
{
Data = t;
}
}
public void AddHead(int t) //T as method parameter type
{
n = new Mode(t);
n.Next = head;
head = n;
}
}
the new object will save over the previous object n.Next?
In a LinkedList, the Next property of a list node doesn’t save or manipulate anything about the list, it just returns the Next item that the node is pointing to. The item returned is also a Node, that has its own Next, that points to yet another item in the list. If you repeatedly call Next then you simply travel along the list
Think of it as trying to find your child. You know he went to john’s house. You go to john’s house but are told “they went to paul’s house”, so you go to paul’s house and are told “they went to Sarah’s house”, so you go to Sarah’s house...
At each step you’re being sent to the Next house, but you’re not demolishing anyone’s house. You maintain a memory of where you are in the list of houses. If you went back to johns house and started over (the list head) you would travel the same route again
If you were to make a new variable pointing to the head of the list, and then repeatedly reassign it to Next, then you’re always changing the Node your temp variable is pointing to, but the list nodes themselves always stay pointing to each other too, and you don’t disturb their relationship:
var tempNode = list.Node; //tempNode is you, you’re at john’s house now
tempNode = tempNode.Next; //now you’re at paul’s house
tempNode = tempNode.Next; //now you’re at sarah’s
At no time did you disturb any of the existing nodes. What if, when you got to Paul’s house you said to Paul’s dad “if my wife comes asking, tell her my son went to Jane’s house” - this changes where Paul’s dad will point the next person to:
var tempNode = list.Node; //tempNode is you, you’re at john’s house now
tempNode = tempNode.Next; //now you’re at paul’s house
tempNode.Next = new Node(“Jane’s house”);
Now we have actually manipulated the list and changed where the Next of the second node is pointing to
how does AddHead work?
It takes the data you pass in and makes a new Node out of it, then makes the new node's Next point to the existing list head and makes the existing list head point to the new node instead. This effectively makes the list grow backwards by adding a new head all the time. If you wanted the houses to be visited in order of John, Paul, Sarah you'd have to add them in order of AddHead(Sarah), AddHead(Paul), AddHead(John)
The list growth looks like:
head->nothing
head->Sarah
head->Paul->Sarah
head->John->Paul->Sarah
I simplified the look of this, to hide Nodes and Next. Every arrow -> represents Next, every name is the Data inside a Node
how do I post code
Put 3 back ticks on their own line, before and after the code block. Or prefix every line in the code with 4 or more spaces
how should I name the question
That’s really for you to decide, as it helps us understand how you think as does the question body

Use string variable to identify corresponding instance of a class

I have a simple class to define rooms. Initially I set up all the rooms I need, (Could be hundreds in a long list), though in my example I set up just 3. Then I have a string that I will use to reference the right instance of Rooms class. For instance, this could be "X10Y10". I want to use that string to identify the corresponding Rooms instance, but don't know how to associate them.
void Start () {
Rooms X10Y10 = new Rooms();
X10Y10.Name = "The Great Room";
X10Y10.RoomMonsters = 10;
X10Y10.Ref = "001";
Rooms X11Y10 = new Rooms();
X11Y10.Name = "Smoking room";
X11Y10.RoomMonsters = 2;
X11Y10.Ref = "002";
Rooms X12Y10 = new Rooms();
X12Y10.Name = "Hunting Room";
X12Y10.RoomMonsters = 7;
X12Y10.Ref = "003";
// Don't Know the room Ref until runtime, during game.
// Want to get the room instance properties of one of the rooms eg.
string RoomAtRuntime = "X11Y10"; // dont know this until game is running
// fix following lines
print(RoomAtRuntime.RoomMonster); // would return 2
print(RoomAtRuntime.Name); // would return Smoking room
}
public class Rooms
{
public string Ref { get; set; }
public string Name { get; set; }
public int RoomMonsters { get; set; }
}
It sounds like what you need here is a Dictionary - a collection which associates Keys with Values. In your case, you can associate each string key with a different Rooms instance, making it easy (and efficient) to quickly access any instance. Here's what your code might look like with this change:
// Declare and initialize dictionary before using it
private Dictionary<string, Rooms> roomCollection = new Dictionary<string, Rooms>();
void Start () {
// After you instantiate each room, add it to the dictionary with the corresponding key
Rooms X10Y10 = new Rooms();
X10Y10.Name = "The Great Room";
X10Y10.RoomMonsters = 10;
X10Y10.Ref = "001";
roomCollection.Add("X10Y10", X10Y10);
Rooms X11Y10 = new Rooms();
X11Y10.Name = "Smoking room";
X11Y10.RoomMonsters = 2;
X11Y10.Ref = "002";
roomCollection.Add("X11Y10", X11Y10);
Rooms X12Y10 = new Rooms();
X12Y10.Name = "Hunting Room";
X12Y10.RoomMonsters = 7;
X12Y10.Ref = "003";
roomCollection.Add("X12Y10", X12Y10);
// The rooms should now all be stored in the dictionary as key-value pairs
string RoomAtRuntime = "X11Y10";
// Now we can access any room by its given string key
print(roomCollection[RoomAtRuntime].RoomMonster);
print(roomCollection[RoomAtRuntime].Name);
}
Note that you may need to add the directive using System.Collections.Generic to your script file.
You can (and probably should) also use something other than a string for your key value. Here, I think it'd make more sense to use a Vector2 value for these X/Y coordinates, rather than strings. (So, something like roomCollection.Add(new Vector2(10, 10), X10Y10); would be more appropriate.)
Hope this helps! Let me know if you have any questions.

C# - fastest way of comparing a collection against itself to find duplicates

public class TestObject
{
string TestValue { get; set; }
bool IsDuplicate { get; set; }
}
List<TestObject> testList = new List<TestObject>
{
new TestObject { TestValue = "Matt" },
new TestObject { TestValue = "Bob" },
new TestObject { TestValue = "Alice" },
new TestObject { TestValue = "Matt" },
new TestObject { TestValue = "Claire" },
new TestObject { TestValue = "Matt" }
};
Imagine testList is actually millions of objects long.
What's the fastest way to ensure that two of those three TestObjects with TestValue of Matt gets its IsDuplicate set to true? No matter how may instances of a given value there are, only one should come out of the process with IsDuplicate of false.
I am not averse to doing this via threading. And the collection doesn't have to be a list if converting it to another collection type is faster.
I need to keep duplicates and mark them as such, not remove them from the collection.
To expand, this is (as you might imagine) a simple expression of a much more complex problem. The objects in question already have an ordinal which I can use to order them.
After matching initial duplicates on exact string equality, I'm going to have to go back through the collection again and re-try the remainder using some fuzzy matching logic. The collection that exists at the start of this process won't be changed during the deduplication, or afterwards.
Eventually the original collection is going to be written out to a file, with likely duplicates flagged.
As others mentioned, the correct approach here would be to use the HashSet class.
var hashSet = new HashSet<string>();
foreach (var obj in testList)
{
if (!hashSet.Add(obj.TestValue))
{
obj.IsDuplicate = true;
}
}
When you add a value first time to the HashSet, it adds successfully and HashSet.Add() method returns true so you don't make any changes to the item. When you're trying to add it second time, HashSet.Add() returns false and you mark your item as a duplicate.
The list will have the following state after finishing running our marking duplicates method:
Matt
Bob
Alice
Claire
Matt DUPLICATE
This is probably quite performant:
foreach (var dupe in testList.GroupBy(x => x.TestValue).SelectMany(g => g.Skip(1)))
dupe.IsDuplicate = true;
[EDIT] This method turns out to be about a third of the speed of the accepted answer above, so that one should be used. This answer is merely of academic interest.
Probably I would go to check for the duplicates while building the collection of the TestValue to avoid looping two times on millions of elements. If this scenario is possible then I would use a Dictionary<string, List<TestValue>>
Dictionary<string, List<TestValue>> myList = new Dictionary<string, List<TestValue>>();
while(NotEndOfData())
{
TestValue obj = GetTestValue();
if(myList.ContainsKey(obj.Name))
{
obj.IsDuplicate = true;
myList[obj.Name].Add(obj);
}
else
{
obj.IsDuplicate = false;
myList.Add(obj.Name, new List<TestValue>() { obj};
}
}
SortedSet<string> sorted = new SortedSet<string>();
for (int i = 0; i < testList.Count; i++)
testList[i].IsDuplicate = !sorted.Add(testList[i].TestValue);
As you have allowed in the question, I'd change testList to be an array instead of a list, to make indexer faster.
Since you indicated that you have a property that keeps the ordinal of your items. We can use that property to reset the sort order back to its original after marking our items as duplicates.
The code below is self-explainatory. But just let me know in case you need any further explaination.
I have assumed that the property name is SortOrder. Modify the code accordingly.
void MarkDuplicates()
{
testList = testList.OrderBy(f => f.TestValue).ThenBy(f => f.SortOrder).ToList();
for (int i = 1; i < testList.Count; i++)
{
if (testList[i].TestValue == testList[i - 1].TestValue) testList[i].IsDuplicate = true;
}
testList = testList.OrderBy(f => f.SortOrder).ToList();
}
I'm not a performance expert. But you can time the various solutions provided here and check the performance for yourself.

Update All References to Cached Object in Dictionary

I have a simple cache of objects:
Dictionary<int, Person> personCache = ...
personCache.Add(1, new Person(){ID = 1, Name = "John"});
personCache.Add(2, new Person(){ID = 2, Name = "Mary"});
personCache[1].Manager=personCache[2];
(In reality, I have proper encapsulation of the dictionary)
So now John's manager is set to Mary. However, if I want to replace Mary with a new instance of person, if I do
personCache[2] = new Person(){ID = 2, Name = "Kate"});
References to Mary are not replaced with references to Kate - i.e. John's manager is not updated.
I can see why this is - the dictionary has a reference to Kate, but John still holds a reference to Mary.
Can anyone suggest a way such that
personCache[2] = new Person(){ID = 2, Name = "Kate"});
Would have the 'expected' result and replace all references to Mary with a reference to Kate?
I think I need to obtain the reference stored in personCache[2] and change that reference to a new person.
Thank you
Ryan
Why not just search for the Manager directly and updated it where it points to the old value
Person oldPerson = personCache[2];
Person newPerson = new Person() { ID = 2, Name = "Kate" };
personCache[2] = newPerson;
foreach (var pair in personCache) {
if (pair.Value.Manager == oldPerson) {
pair.Vaulue.Manager = newPerson;
}
}
"... Would have the 'expected' result "
I believe it already has what most people would consider to the the expected result.
One way to achieve what you appear to want is to make the Name property of your Person class writable, then do:
personCache[2].Name = "Kate";
Another approach would be to store only the Id of the manager in your Person object, rather than a reference to the Manager. I.e. instead of:
personCache[1].Manager = personCache[2];
You could have:
personCache[1].ManagerId = 2;
And you could, for example, have an extension method to get the Manager for a Person:
public static Person GetManager(this Person person)
{
if (person == null) throw new ArgumentNullException("person");
Person manager;
personCache.TryGetValue(person.ManagerId, out manager);
return manager; // returns null if not found in cache
}

How to replace a list item with direct instance assignment

I have the following code where I'm trying 3 approaches (Cases) to update the first item in a C# list(Note: Dump() is a helper output method in the LINQPad IDE). I would appreciate an explanation as to why Case 2 does not succeed in updating the list while Case 3 does. Both first and list[0] are references to the first item in the list and should behave equivalently when assigned a direct reference. Apparently not...
void Main()
{
Person first = null;
List<Person> list = CreateList(out first);
//Case 1
//This updates the list
first.fname = "Third";
list.Dump(); //outputs third, second
//Case 2
//This does not update the list
list = CreateList(out first);
first= new Person() { fname="Third"};
list.Dump(); //outputs first, second
//Case 3
//This updates the list
list = CreateList(out first);
list[0] = new Person() { fname="Third"};
list.Dump(); //outputs third, second
}
List<Person> CreateList(out Person first)
{
var list = new List<Person>
{
new Person() { fname="First", lname = ""},
new Person() { fname="Second", lname = ""}
};
first = list.Find( x => x.fname == "First");
return list;
}
// Define other methods and classes here
class Person
{
public string fname;
public string lname;
}
The second case doesn't work because you change the reference for the first to the new object using this code:
first= new Person() { fname="Third"};
After this code run, the first is not refer to list object again.
Try to use this for the second case:
list = CreateList(out first);
if(first != null)
first.fname="Third";
list.Dump();
This will set the property of first and the first is still refer to the list item.
when you pass a new object to a reference object
first= new Person() { fname="Third"};
you generate a new object with a new hashcode upon which the object is identified in collection.the list does not find the previous hascode and thus list is not updated.//case 2
but in case 3 you are replacing the instance of object and thereby list updates the new hash
in case 1 you modify only property of an object and the hash remains intact
may be this be explanation to your problem

Categories