I am holding two lists in my program - one master list and another temporary list which is constantly being updated. Every so often, the temporary list flushes into the master list.
The master list is HashSet (for no-duplicates) and the temporary list is List (for indexing capability). I flush the latter into the former by calling
HashSet<T>.UnionWith(List<T>)
In my testing, I find that duplicates make their way into the list, yet I thought this wasn't possible in a HashSet. Can someone please confirm/correct this? I haven't been able to find it in MSDN.
It isn't possible if your type overrides GetHashCode() and Equals() correctly. My guess is that your type hasn't done this properly. (Or your hash set has been created with a custom equality comparer which doesn't do what you want.)
If you believe that's not the case, please post the code :)
But yes, it really will prevents duplicates when used normally.
List (for indexing capability).
You'd want a dictionary for indexing.
On that note though, here's a very simple program that illustrates your problem:
class Program
{
static void Main(string[] args)
{
int totalCats = 0;
HashSet<Cat> allCats = new HashSet<Cat>();
List<Cat> tempCats = new List<Cat>();
//put 10 cats in
for (int i = 0; i < 10; i++)
{
tempCats.Add(new Cat(i));
totalCats += 1;
}
//add the cats to the final hashset & empty the temp list
allCats.UnionWith(tempCats);
tempCats = new List<Cat>();
//create 10 identical cats
for (int i = 0; i < 10; i++)
{
tempCats.Add(new Cat(i));
totalCats += 1;
}
//join them again
allCats.UnionWith(tempCats);
//print the result
Console.WriteLine("Total cats: " + totalCats);
foreach (Cat curCat in allCats)
{
Console.WriteLine(curCat.CatNumber);
}
}
}
public class Cat
{
public int CatNumber { get; set; }
public Cat(int catNum)
{
CatNumber = catNum;
}
}
Your problem is that you aren't overriding GetHashCode() and Equals(). You need to have both for the hash set to stay unique.
This will work, however the GetHashCode() function should be much more robust. I'd recommend reading up how .NET does it:
class Program
{
static void Main(string[] args)
{
int totalCats = 0;
HashSet<Cat> allCats = new HashSet<Cat>();
List<Cat> tempCats = new List<Cat>();
//put 10 cats in
for (int i = 0; i < 10; i++)
{
tempCats.Add(new Cat(i));
totalCats += 1;
}
//add the cats to the final hashset & empty the temp list
allCats.UnionWith(tempCats);
tempCats = new List<Cat>();
//create 10 identical cats
for (int i = 0; i < 10; i++)
{
tempCats.Add(new Cat(i));
totalCats += 1;
}
//join them again
allCats.UnionWith(tempCats);
//print the result
Console.WriteLine("Total cats: " + totalCats);
foreach (Cat curCat in allCats)
{
Console.WriteLine(curCat.CatNumber);
}
Console.ReadKey();
}
}
public class Cat
{
public int CatNumber { get; set; }
public Cat(int catNum)
{
CatNumber = catNum;
}
public override int GetHashCode()
{
return CatNumber;
}
public override bool Equals(object obj)
{
if (obj is Cat)
{
return ((Cat)obj).CatNumber == CatNumber;
}
return false;
}
}
Related
Having a model something like this (I cannot change this):
public class SomeObject
{
public int Amount { get; set; }
public int TotalAmount { get; set; }
}
I need to iterate an array of SomeObject to populate some values and accumulate (perform not simple calculations) another fields.
static void Main(string[] args)
{
List<SomeObject> myCollection = new List<SomeObject>()
{
new SomeObject() { Amount = 3 },
new SomeObject() { Amount = 6 },
new SomeObject() { Amount = 9 }
};
int totalAccumulated = 0;
for (int i = 0; i < myCollection.Count; i++)
{
PopulateAndCalculate(myCollection[i], ref totalAccumulated);
}
//I don't want to create here a second for to iterate again all myCollection to set his TotalAmount property.
//There is another way?
Console.WriteLine($"The total accumulated is: {totalAccumulated}");
}
private static void PopulateAndCalculate(SomeObject prmObject, ref int accumulatedTotal)
{
//Populate a lot of another fields
accumulatedTotal += prmObject.Amount;
prmObject.TotalAmount = accumulatedTotal; //This don't work, but I need something alike
}
I don't want a second for statement to update TotalAmount property of each item in myCollection.
The main requirement is iterate the whole array, few times, don't care about string interpolation this is a short demo, this code must run in .net 2.0.
Theres is a clean/better way?
The solution is actually simple, though it's not exactly a good coding practice.
What you really need is for TotalAmount to be a static property. Without that, there's this:
static void Main(string[] args)
{
List<SomeObject> myCollection = new List<SomeObject>()
{
new SomeObject() { Amount = 3 },
new SomeObject() { Amount = 6 },
new SomeObject() { Amount = 9 }
};
int totalAccumulated = 0;
for (int i = 0; i < myCollection.Count; i++)
{
PopulateAndCalculate(myCollection[i], ref totalAccumulated);
}
/*****This is the new part*******/
myCollection[0].TotalAmount = totalAccumulated;
myCollection[1].TotalAmount = totalAccumulated;
myCollection[2].TotalAmount = totalAccumulated;
Console.WriteLine($"The total accumulated is: {totalAccumulated}");
}
private static void PopulateAndCalculate(SomeObject prmObject, ref int accumulatedTotal)
{
//Populate a lot of another fields
accumulatedTotal += prmObject.Amount;
//no need to mess with the total here as far as the properties are concerned.
}
You can st fields inside linq expression.
Could you consider this please
myCollection.ForEach(c => c.TotalAmount = myCollection.Sum(a => a.Amount));
Console.WriteLine($"Total accumulated :{myCollection.First().TotalAmount}");
I found a solution using the Observer Pattern.
Firstly I created a global delegate to be used by an event:
public delegate void UpdateTotalAmountDelegate(int totalAmount);
Then a new class called: 'CalculatorSetter'
public class CalculatorSetter
{
public event UpdateTotalAmountDelegate UpdateTotalAmounthHandler;
public void UpdateTotalAmount(int prmTotalAmount)
{
UpdateTotalAmounthHandler(prmTotalAmount);
}
}
I refactor the data object 'SomeObject' adding a field of type CalculatorSetter.
public class SomeObject
{
private CalculatorSetter finalCalculator;
public void SetCalculator(CalculatorSetter prmCalculator)
{
this.finalCalculator = prmCalculator;
finalCalculator.UpdateTotalAmounthHandler += FinalCalculator_UpdateTotalAmounthHandler;
}
private void FinalCalculator_UpdateTotalAmounthHandler(int totalAmount)
{
this.TotalAmount = totalAmount;
}
//Some Other Fields
public int Amount { get; set; }
public int TotalAmount { get; set; }
}
And my original code and unique for:
static void Main(string[] args)
{
List<SomeObject> myCollection = new List<SomeObject>()
{
new SomeObject() { Amount = 3 },
new SomeObject() { Amount = 6 },
new SomeObject() { Amount = 9 }
};
CalculatorSetter commonCalculator = new CalculatorSetter();
int totalToAccumulate = 0;
for (int i = 0; i < myCollection.Count; i++)
{
PopulateAndCalculate(myCollection[i], commonCalculator, ref totalToAccumulate);
}
commonCalculator.UpdateTotalAmount(totalToAccumulate);
Console.WriteLine($"The total accumulated is: {totalToAccumulate}");
Console.WriteLine($"The first total accumulated is: {myCollection[0].TotalAmount}");
}
Many thanks.
Use a wrapper and keep it simple (if you want you can change a little for use static methods you can, or static class but I dont see the point)
the result is:
The Amount is 3, The total ammount is 18
The Amount is 6, The total ammount is 18
The Amount is 9, The total ammount is 18
namespace Prueba1
{
class Program
{
public class WrapperInt {
public int Value { get; set; }
}
public class SomeObject
{
public int Amount { get; set; }
public WrapperInt TotalAmount { get; set; }
}
public Program() {
WrapperInt TotalAmountAllArrays = new WrapperInt();
List<SomeObject> myCollection = new List<SomeObject>()
{
new SomeObject() { Amount = 3, TotalAmount =TotalAmountAllArrays },
new SomeObject() { Amount = 6 , TotalAmount =TotalAmountAllArrays },
new SomeObject() { Amount = 9 , TotalAmount =TotalAmountAllArrays }
};
for (int i = 0; i < myCollection.Count; i++)
{
myCollection[i].TotalAmount.Value += myCollection[i].Amount;
}
foreach (var c in myCollection)
{
Console.WriteLine($"The Amount is:" + c.Amount + " The total ammount is:" + c.TotalAmount.Value);
}
}
static void Main(string[] args)
{
new Program();
}
}
}
Hopefully this will work for you… One possible solution is to create a wrapper class called MyTotalList which contains a List named amounts and an int named total. MyTotalList class does not expose its list amounts as an editable list. If the class exposes this list as editable, then other methods could ultimately change an items value in that list and the MyTotalList class would not be aware of this and unfortunately contain an incorrect total. To avoid this situation and for the class to work as expected, methods must use the MyTotalList’s Add and Remove methods. To ensure this happens, the private List amounts in the MyTotalList class returns a read only list which ensures that changes to the list will not be made outside the MyTotalList class. Leaving the list exposed and editable will/could cause the class to contain an incorrect total.
My solution is to create a Class that wraps a List. MyTotalList class has a no argument constructor. Once a new instance of a MyTotalList object is created you can then use that instance to Add MyObject items to its list. Every time an item is added to the MyTotalList, list amounts the variable total gets updated with the added item’s amount. Example:
Create a new MyTotalList object:
MyTotalList listOfObjects = new MyTotalList();
Then add some MyObject instances to the listOfObjects
listOfObjects.Add(new MyObject(1,3));
listOfObjects.Add(new MyObject(2,6));
listOfObjects.Add(new MyObject(3,9));
After you add the items, you can then use the listOfObjects Total property to get the total sum of all MyObject items in the list with:
listOfObjects.Total
If you need to pass or use the List of MyTotalList items you can use:
listOfObjects.Items
Bear in mind as I discussed above, this List Items is a read-only list. Therefore you cannot add/remove items in this list as you would an editable list. So the code below will fail during implementation as these methods are not exposed for read only objects.
listOfObjects.Items.Remove(new MyObject(4, 10));
listOfObjects.Items.Add(new MyObject(4, 10));
The above lines will cause the compiler to complain: xxx… does not contain a definition for Add/Remove. This ensures methods will use the MyTotalList.Add and MyTotalsList.Remove methods and eliminate any possibility of the list changing outside the MyTotalList class.
MyObject Class
class MyObject : IComparable {
public int id { get; }
public int amount { get; }
public MyObject(int inID, int inAmount) {
id = inID;
amount = inAmount;
}
public override string ToString() {
return amount.ToString();
}
public override int GetHashCode() {
return id.GetHashCode();
}
public override bool Equals(object other) {
if (other != null)
return (this.id == ((MyObject)other).id);
return false;
}
public int CompareTo(object other) {
if (this.id > ((MyObject)other).id)
return 1;
if (this.id < ((MyObject)other).id)
return -1;
return 0;
}
}
MyTotalList Class
class MyTotalList {
private int total;
private List<MyObject> amounts;
public MyTotalList() {
total = 0;
amounts = new List<MyObject>();
}
public int ListCount {
get { return amounts.Count; }
}
public IReadOnlyCollection<MyObject> Items {
get { return amounts.AsReadOnly(); }
}
public int Total {
get { return total; }
}
public void Add(MyObject other) {
if (other != null) {
if (!(amounts.Contains(other))) {
total += other.amount;
amounts.Add(other);
}
else {
Console.WriteLine("Duplicate id's not allowed!");
}
}
}
public void Remove(MyObject other) {
if (amounts.Contains(other)) {
total -= amounts[amounts.IndexOf(other)].amount;
amounts.Remove(other);
}
else {
Console.WriteLine("Item to remove not found!");
}
}
}
Examples
MyTotalList listOfObjects = new MyTotalList();
listOfObjects.Add(new MyObject(1,3));
listOfObjects.Add(new MyObject(2,6));
listOfObjects.Add(new MyObject(3,9));
Console.WriteLine("----------------------------------------");
Console.WriteLine("Initial list with total");
Console.WriteLine("items in list:");
foreach (MyObject mo in listOfObjects.Items)
Console.Write(mo.ToString() + " ");
Console.WriteLine();
Console.WriteLine("Total from list of " + listOfObjects.ListCount +
" items is: " + listOfObjects.Total);
Console.WriteLine("----------------------------------------");
Console.WriteLine("Add three more items");
listOfObjects.Add(new MyObject(4, 10));
listOfObjects.Add(new MyObject(5, 11));
listOfObjects.Add(new MyObject(6, 12));
Console.WriteLine("items in list:");
foreach (MyObject mo in listOfObjects.Items)
Console.Write(mo.ToString() + " ");
Console.WriteLine();
Console.WriteLine("Total from list of " + listOfObjects.ListCount +
" items is: " + listOfObjects.Total);
Console.WriteLine("----------------------------------------");
Console.WriteLine("Remove id 4 (10) from the list");
listOfObjects.Remove(new MyObject(4, 10));
Console.WriteLine("items in list:");
foreach (MyObject mo in listOfObjects.Items)
Console.Write(mo.ToString() + " ");
Console.WriteLine();
Console.WriteLine("Total from list of " + listOfObjects.ListCount +
" items is: " + listOfObjects.Total);
A Side note to your original post…About the class you can not change
SomeObject {
public int Amount { get; set; }
public int TotalAmount { get; set; }
}
Regardless of how you get the total for theint varable: TotaAmount… for each instance of SomeObject class to contain the same variable with the same amount and you want to ensure this is true for all existing SomeObject instances… is well a poor design. This creates redundant data and simply waste space and it makes no sense for each variable to contain this value as it has absolutely nothing to do with that SomeObject instance. This class design is counter intuitive of a good design. As #Tim Schmelter’s comment points out "a single object should not know anything about the total amount of other objects." This “redundant data” situation is something a programmer should try to avoid, not promote.
I have a class as below,
class EUInput
{
public EUInput()
{
RtID = 0;
}
public int RtID { get; set; }
}
I want to store this class with different RtID values in a list. I tried as below,
static void Main(string[] args)
{
EUInput clsEUInput = new EUInput();
List list = new List();
for (int i = 0; i < 5; i++)
{
clsEUInput.RtID = i;
list.Add(clsEUInput);
}
foreach (EUInput obj in list)
{
Console.WriteLine(obj.RtID.ToString());
}
Console.ReadLine();
}
I am getting an output as
4
4
4
4
4
But I need an outupt as
0
1
2
3
4
You need to move the declaration of clsEUInput inside the for loop. Right now, there is only one EUInput object and you're adding the same object to the list multiple times.
List list = new List();
for (int i = 0; i < 5; i++)
{
EUInput clsEUInput = new EUInput();
clsEUInput.RtID = i;
list.Add(clsEUInput);
}
Change EUInput to be a struct (and keep your Main method as it is):
public struct EUInput
{
public int RtID;
}
A struct is a value type (a class is a reference type), so when you add it to a list, you basically add a "copy" of the whole structure (and not just a reference). So when you keep changing the RtID in the loop, you still change that one object you created, but the objects in the list won't be affected.
Either your boss is playing a trick on you, i.e. want's to test your knowledge about value types and reference types, or he doesn't know about the difference between them himself...
you Need new instances to the class
or the complete list will hold references to the one instance
private class EUInput
{
public EUInput()
{
RtID = 0;
}
public int RtID { get; set; }
}
//I want to store this class with different RtID values in a list. I tried as below,
private static void Main(string[] args)
{
List<EUInput> list = new List<EUInput>();
for (int i = 0; i < 5; i++)
{
EUInput clsEUInput = new EUInput();
clsEUInput.RtID = i;
list.Add(clsEUInput);
}
foreach (EUInput obj in list)
{
Console.WriteLine(obj.RtID.ToString());
}
Console.ReadLine();
}
I have a list with 1000000 items and I need to figure out if a item is inside but by reference. Therefore I can't use Contains since Contains doesn't always match by reference (e.g. when list of type string). I tried list.Any(x => object.ReferenceEquals) but that is too slow.
Take a look here:
for(int i = 0; i < 1000000; i++)
{
if(does list contains this item anotherList[i])
{
list.Add(anotherList[i]);
}
}
How do I perform this really fast?
Use a dictionary with an IdendityEqualityComparer to get the key comparison in the dictionary to do a reference comparison. The main difference between this approach and yours is that you have an O(1) lookup, instead of an O(n) lookup that you get from having to go through an entire list for each item.
Put the following code inside a sample Console app project; it basically splits a master dictionary into two.
public class IdentityEqualityComparer<T> : IEqualityComparer<T> where T : class
{
public int GetHashCode(T value)
{
return RuntimeHelpers.GetHashCode(value);
}
public bool Equals(T left, T right)
{
return left == right; // Reference identity comparison
}
}
public class RefKeyType
{
public int ID { get; set; }
}
class Program
{
public static void Main()
{
var refDictionary = new Dictionary<RefKeyType, int>(1000000, new IdentityEqualityComparer<RefKeyType>());
var testDictionary = new Dictionary<RefKeyType, int>(1000000, new IdentityEqualityComparer<RefKeyType>());
var store = new Dictionary<RefKeyType, int>(1000000);
for (var i = 0; i < 1000000; i++)
{
var key = new RefKeyType() {ID = i};
refDictionary[key] = i;
//Load the test dictionary if I is divisible by 2
if (i%2 == 0)
{
testDictionary[key] = i;
}
}
foreach (var key in refDictionary.Keys)
{
int val;
if (!testDictionary.TryGetValue(key, out val))
{
store[key] = val;
}
}
Console.WriteLine("Master dictionary has " + refDictionary.Count);
Console.WriteLine("Test dictionary has " + testDictionary.Count);
Console.WriteLine("Store dictionary has " + store.Count);
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
I was making a custom grid that accepts an IEnumerable as an Itemsource. However I was not able to remove an Item inside the itemsource during delete method. Will you guys be able to help me using the code below?
static void Main(string[] args)
{
List<MyData> source = new List<MyData>();
int itemsCount = 20;
for (int i = 0; i < itemsCount; i++)
{
source.Add(new MyData() { Data = "mydata" + i });
}
IEnumerable mItemsource = source;
//Remove Sample of an mItemSource
//goes here ..
}
public class MyData { public string Data { get; set; } }
You can't. IEnumerable (and its generic counterpart IEnumerable<T>) is for just that - enumerating over the contents of some collection. It provides no facilities for modifying the collection.
If you are looking for an interface that provides all the typical means of modifying a collection (eg. Add, Remove) then have a look at ICollection<T> or IList<T> if you need to access elements by index.
Or, if your goal is to provide an IEnumerable to something, but with some items removed, consider Enumerable.Except() to filter them out (as it is enumerated).
Use while loop to traverse the list whilst delete.
int i = 0;
while(i < source.Count){
if(canBeRemoved(source[i])){
source.RemoveAt(i);
}else{
i++;
}
}
I was able to remove Item from the Itemsource using dynamic
static void Main(string[] args)
{
List<MyData> source = new List<MyData>();
int itemsCount = 20;
for (int i = 0; i < itemsCount; i++)
{
source.Add(new MyData() { Data = "mydata" + i });
}
IEnumerable mItemsource = source;
//Remove Sample of an mItemSource
dynamic d = mItemsource;
d.RemoveAt(0);
//check data
string s = source[0].Data;
}
public class MyData { public string Data { get; set; } }
I have the following class. Inside of the Parent class is a List of ParentDetail. Now I need to add a new field to the ParentDetail class. The field is called Id. What I need is a method in the main class that will iterate through the ParentDetails and populate the Id field with a number starting at 1.
Can anyone think of an easy way to do this? I am not sure how I can iterate through the List.
public class Parent {
public IList<ParentDetail> ParentDetails {
get { return _ParentDetails; }
}
private List<ParentDetail> _ParentDetails = new List<ParentDetail>();
public Parent() {
this._ParentDetails = new List<ParentDetail>();
}
}
public class ParentDetail {
public int Id { get; set; } <<<<<<<< new field
}
}
for(int i = 0; i < _ParentDetails.Count; i++)
{
_ParentDetails[i].Id = i + 1;
}
Could do a straight for(int i; i < Count; i++) loop as suggested by Roy Dictus (+1 from me) - I'm just chucking this up there as an alternative, which is very useful in situations where you don't know the count of an enumerable.
foreach(var detail in _ParentDetails.
Select((d, i) => new { Item = d, Index = i + 1})
{
detail.Item.Id = detail.Index;
}
In your case you do; as you have an IList, however.