Two dictionaries intersection C# [duplicate] - c#

This question already has answers here:
Intersect with a custom IEqualityComparer using Linq
(2 answers)
C# Linq intersect/except with one part of object
(7 answers)
Closed 5 years ago.
I had two DateTime lists and was intersecting them with no problems:
IEnumerable<DateTime> both = list1.Intersect(list2);
I have the custom data type and still need to find the intersection:
public class AssetRecord
{
// Custom data type. Each object has time and price
public DateTime AssetDate { get; set; }
public double AssetPrice { get; set; }
}
// Lits initialization
public static List<AssetRecord> list1 = new List<AssetRecord> { };
// Key/Values - Date/Price. Custom data type is used to store an object in the collection
public static List<AssetRecord> list2 = new List<AssetRecord> { };
The problem is that IEnumerable takes only DataTime lists as an input and I do not have that data type anymore. Is it possible to find intersection using custom types? Or is it possible to take only Date field from created data type and convert it to List and then pass it to IEnumerable?

The problem is that IEnumerable takes only DataTime lists
Huh? That makes no sense. IEnumerable<T> takes whatever T you choose. In this case IEnumerable<AssetRecord> will contain AssetRecords.
Now, that is not your main problem. Your issue is with how intersect works. Enumerable.Intersect<T> takes the default equality of T. So, what is the default equality comparer of AssetRecord? Reference equality, and you probably want value equality semantics.
Solution? Override Equals in AssetRecord accordingly and while your at it implement IEquatable<AssetRecord> too (and don't forget to override GetHashCode with a consistent behavior):
public class AssetRecord: //IEquatable<AssetRecord> left as exercise
{
// Custom data type. Each object has time and price
public DateTime AssetDate { get; set; }
public decimal AssetPrice { get; set; }
public override bool Equals(object other)
{
if (other is AssetRecord)
{
var ass = (AssetRecord)other;
return ass.AssetDate == AssetDate &&
ass.AssetPrice == AssetPrice;
}
return false;
}
public override int GetHashCode()
{
return AssetDate.GetHashCode() ^ AssetPrice.GetHashCode();
}
}
If you can't touch AssetRecord then implement an IEqualityComparer<AssetRecord> and use the corresponding overload of Intersect.
Two more issues with your code worth mentioning:
Prices should be a decimal, not a double. You want exact decimal values, use the right tool provided by the framework.
Your type is already named AssetRecord, it should probably be named Asset, but anyway, there is no need to have properties with redundant information. Price and Date should be enough.

Related

Sort (Array array, System.Collections.IComparer? comparer) - parameter or implementation?

The Methode Array.Sort() has the following signature
public static void Sort (Array array, System.Collections.IComparer? comparer);
It looks like you need to pass an IComparer reference. But what is really needed is that array needs to implements IComparable, isn't it?
I see this syntax the first time. Is this common? How can I differentiate between a real parameter? Is there somewhere more information about this topic (in general)?
Important/Edit: ATM I'm reading a C# book and it says about Sort.Array (translated from German to English):
To the first parameter we pass the array to be sorted, in our case
arr. The second parameter is of type IComparer interface. Of course,
you can't pass an instance of type IComparer to the method call,
because interfaces are not instantiable. This is not how the type
specification of the second parameter should be understood. Instead,
the second parameter simply requires that the fist argument passed to
it be an object that implements the interface IComparer - whether the
object is of type DemoClass, Circle,
Basically he says that the second parameter is kind of a description for the first parameter. Is he correct or maybe that's just wrong and the source for my confusion?
https://openbook.rheinwerk-verlag.de/visual_csharp_2012/1997_04_008.html
I just implemented the following snippet. So this could be a way how to pass the second parameter, right?
Array.Sort(shapes, (a, b) => {
if (a.GetArea() < b.GetArea()) return -1;
else if (a.GetArea() > b.GetArea()) return 1;
return 0;
});
If you do not pass the comparer it will use the default comparer implementation for the Array items. But if you have a special comparer then you can pass your own custom Comparer to sort the elements.
Suppose you have a Class of Students (Array of Students), and your default Student comparer can be based on total marks. However, a maths teacher may want to sort the Students based on marks for the Maths only, in that case maths teacher can write his custom MathsRankComparer and pass it to the Sort method so that he will get the Students ordered by marks in Maths.
Similarly, English or Science teacher can pass the respective comparers to get their required ranking/ordering/sorting.
Hope this helps in understanding use of that overload.
Update: some examples to understand details.
public class Student: IComparable<Student>
{
public int ID { get; set; }
public string Name { get; set; }
public float TotalMarks { get; set; }
public float ScienceMarks { get; set; }
public float MathsMarks { get; set; }
public float EnglishMarks { get; set; }
public int CompareTo(Student other)
{
if (this.TotalMarks == other.TotalMarks)
return 0;
if (this.TotalMarks < other.TotalMarks)
return -1;
return 1;
}
}
public class MathsMarksBasedComparer : System.Collections.Generic.IComparer<Student>
{
public int Compare(Student a, Student b)
{
if (a.MathsMarks == b.MathsMarks)
return 0;
if (a.MathsMarks < b.MathsMarks)
return -1;
return 1;
}
}
public class EnglishMarksBasedComparer : System.Collections.Generic.IComparer<Student>
{
public int Compare(Student a, Student b)
{
if (a.EnglishMarks == b.EnglishMarks)
return 0;
if (a.EnglishMarks < b.EnglishMarks)
return -1;
return 1;
}
}
And finally, you can use them like this.
Student[] arr = new Student[100]; // Ignore this, you can use other styles of declaration
Array.Sort(arr, new EnglishMarksBasedComparer());
Array.Sort(arr, new MathsMarksBasedComparer());
Array.Sort(arr);
Basically he says that the second parameter is kind of a description for the first parameter. Is he correct or maybe that's just wrong and the source for my confusion?
It's not wrong it's just worded a bit confusingly.
The IComparer is a nullable type (defined by the questionmark at the end of IComparer). This states that the IComparer is optional/does not have to be passed. However as Mahesh Bongani already meantioned in his reply - internaly if you do not provide a comparer it takes the defualt comparer of the object.
So for this particular funtion if you would pass a Array with objects that do not implement a comparable the function wouldn't be able to sort the elements properly.
I have seen IComparer a few times and am unsure what implements it as standard - as far as lists, arrays and things go. I do know that numbers implement it and I think string does too.
You can though custom implement this inferface. If memory serves me correctly, it provides just one method (interface so you have to write logic yourself) that returns an int. -1 (<0) is lower ranked, +1(>0) is higher ranked, 0 is the same.

C# How to override Dictionary ContainsKey [duplicate]

This question already has answers here:
Dictionary.ContainsKey return False, but a want True
(12 answers)
Closed 2 years ago.
public class Date
{
public int mm;
public int dd;
public Date(int get_mm, int get_dd)
{
mm = get_mm;
dd = get_dd;
}
}
public Dictionary<Date, int> dictionary = new Dictionary<Date, int>();
Date A = new Date(1,1)
Date B = new Date(1,1)
dictionary.Add(A,1);
if(dictionary.ContainsKey(B)) //returns false
...
How do i override the Date class in this situation?
I know the 2 objects is not the same, but don't know how to make it work
You have 2 ways :
By overriding the GetHashCode and Equals method of you class Date.
By using the Dictionary constructor that accepts one IEqualityComparer<Key> as argument.
It is not recommended to use the first method if your Date object is not immutable (i.e. that its attributes can't be modified after its creation => Date attributes need to be readonly). Because the Dictionary class builds its internal structure based on GetHashCode value at insert time. If the attributes used to compute the GetHashCode change, you won't be able to retrieve your objects already inserted in the dictionary.

More informative comparison of objects in C#

In my C# testing, I often want to compare two objects of the same type (typically an expected object against the actual object), but I want to allow for some flexibility. For example, there may be timestamp fields that I know can't be equal or some fields that I just want to ignore when comparing the objects.
Most importantly, I want to provide an informative message that describes where the two object properties' values differ in order that I can quickly identify what the problem is. For example, a message that says "Source property Name value Fred does not match target property Name value Freda".
The standard Equals and Comparer methods just seem to return ints or Booleans which don't provide enough information for me. At the moment, my object comparison methods return a custom type that has two fields (a boolean and a message), but my thinking is that there must be a more standard way to do this. These days, perhaps a Tuple might be the way to go, but I would welcome suggestions.
"Comparison" might not be the word for what you're trying to do. That word already has a common meaning in this context. We compare objects for equality, which returns a boolean - they are equal or they are not. Or we compare them to see which is greater. That returns an int which can indicate that one or the other is greater, or that they are equal. This is helpful when sorting objects.
What you're trying to do is determine specific differences between objects. I wouldn't try to write something generic that handles different types of objects unless you intend for them to be extremely simple. That gets really complicated as you get into properties that return additional complex objects or collections or collections of complex objects. It's not impossible, just rarely worth the effort compared to just writing a method that compares the particular type you want to compare.
Here's a few interfaces and classes that could make the task a little easier and more consistent. But to be honest it's hard to tell what to do with this. And again, it gets complicated if you're dealing with nested complex properties. What happens if two properties both contain lists of some other object, and all the items in those lists are the same except one on each side that have a differing property. Or what if they're all different? In that case how would you describe the "inequality" of the parent objects? It might be useful to know that they are or are not equal, but less so to somehow describe the difference.
public interface IInstanceComparer<T>
{
IEnumerable<PropertyDifference> GetDifferences(T left, T right);
}
public abstract class InstanceComparer<T> : IInstanceComparer<T>
{
public IEnumerable<PropertyDifference> GetDifferences(T left, T right)
{
var result = new List<PropertyDifference>();
PopulateDifferences(left, right, result);
return result;
}
public abstract void PopulateDifferences(T left, T right,
List<PropertyDifference> differences);
}
public class PropertyDifference
{
public PropertyDifference(string propertyName, string leftValue,
string rightValue)
{
PropertyName = propertyName;
LeftValue = leftValue;
RightValue = rightValue;
}
public string PropertyName { get; }
public string LeftValue { get; }
public string RightValue { get; }
}
public class Animal
{
public string Name { get; }
public int NumberOfLimbs { get; }
public DateTime Created { get; }
}
public class AnimalDifferenceComparer : InstanceComparer<Animal>
{
public override void PopulateDifferences(Animal left, Animal right,
List<PropertyDifference> differences)
{
if(left.Name != right.Name)
differences.Add(new PropertyDifference("Name", left.Name, right.Name));
if(left.NumberOfLimbs!=right.NumberOfLimbs)
differences.Add(new PropertyDifference("NumberOfLimbs",
left.NumberOfLimbs.ToString(),
right.NumberOfLimbs.ToString()));
}
}
You could use extension methods to do this. For example:
public static Extensions
{
public static void CompareWithExpected(this <type> value, <type> expected)
{
Assert.AreEqual(expected.Property1, value.Property1, "Property1 did not match expected";
Assert.AreEqual(expected.Property2, value.Property2, "Property2 did not match expected";
}
}
Then this can be used as follows:
public void TestMethod()
{
// Arrange
...
// Act
...
// Assert
value.CompareWithExpected(expected);
}
You could have any number of these extension methods allowing you the flexibility to check only certain values etc.
This also means you do not need to pollute your types with what is essentially test code.

Exclude complex property with reflection get properties [duplicate]

Is it possible when looking at a class' properties to detect if any of them is a reference type.
Take below as an example:
public class Client
{
public int Id { get; set; }
public string Name { get; set; }
}
public class ProgrammeClient
{
public int Id { get; set; }
public bool IsActive { get; set; }
public IClient Client { get; set; }
}
ProgrammeClient: -
Id and IsActive are properties but Client is a reference type. Is there a way of detecting this?
Many thanks,
Kohan.
Addendum
The reason i ask is: I am using a mapper that checks types are the same before matching property names and copying the values. My hope is to detect classes and override the type matching and simply copy the classes properties if the THEY type match.
Well, it sounds like you may be trying to detect the difference between a value type and a reference type. You can find that out using Type.IsValueType... but be aware that value types can easily have properties too. (Think about DateTime for example.) Also, some types which you may want to regard as "not objects" are reference types - string being a prime example.
Another option would be to use Type.IsPrimitive - is that what you're looking for? If so, you should be aware that decimal, DateTime and string are not primitive types.
If you can describe exactly what makes a type an "object" in your way of thinking (or rather, in whatever way makes a semantic difference in what you're trying to do with your type). I suspect you don't currently have a very clear set of criteria - coming up with those criteria may well clarify other aspects of your current task, too.
You can use a little reflection to see if a property is a value type or a class type. Class is probably what you mean by "object". All types in .NET derive from the object type.
Client.GetType().IsClass
Or you can loop through all properties and see which are compound
foreach(var p in ProgrammeClient.GetType().GetProperties())
{
if(p.PropertyType.IsClass) Console.WriteLine("Found a class");
}
Check if the type is a string and check if it is a class.
public static bool IsNonStringClass(this Type type)
{
if (type == null || type == typeof(string))
return false;
return typeof(Type).IsClass;
}
All properties in your example return objects, as everything is an object in .NET; int and bool are objects. If you mean a reference type, as opposed to value types, then you can do the following:
foreach (PropertyInfo pi in typeof(Client).GetProperties()) {
if (pi.PropertyType.IsClass) {
// reference type
// DoMyFunkyStuff
}
}
You can enumerate the properties via Reflection, and check them:
bool ContainsOnlyValues() {
return typeof(ProgrammeClient).GetProperties().All(x => x.PropertyType.IsValueType);
}
The Type.IsvalueType property can reveal this.
Id.GetType().IsValueType
This will be True for Id, false for a class
If using TypeSupport nuget package you can simply do:
typeof(ProgrammeClient).GetExtendedType().IsReferenceType;
TypeSupport does inspection and provides deeper insight on the capabilities of a given type, handling things like strings, enums etc and makes it easier to code these types of things.

Duplicate values in generic list c#

I'm adding values to a c# generic list while trying to prevent duplicates, but without success. Anyone know of a reason why this code below wouldn't work?
I have a simple class here:
public class DrivePairs
{
public int Start { get; set; }
public int End { get; set; }
}
And here is my method which tries to return a generic list of the above class:
ArrayList found = DriveRepository.GetDriveArray(9, 138);
List<DrivePairs> drivePairs = new List<DrivePairs>();
foreach (List<int> item in found)
{
int count = item.Count;
if (count > 1)
{
for (int i = 0; i < (count - 1); i++)
{
DrivePairs drivePair = new DrivePairs();
drivePair.Start = item[i];
drivePair.End = item[i + 1];
if (!drivePairs.Contains(drivePair))
drivePairs.Add(drivePair);
}
}
}
drivePairs = drivePairs.Distinct().ToList();
As you can maybe see, I have an ArrayList, and each row contains a List<int>. What I'm doing is going through each and adding to a list which contains only pairs. E.g. if my List<int> contains [1,3,6,9] I want to add three entries to my pairs list:
[1,3]
[3,6]
[6,9]
It all works fine apart from not recognising duplicates. I thought this line would be enough:
if (!drivePairs.Contains(drivePair))
drivePairs.Add(drivePair);
but it continues to add them all. Even when I add a Distinct() at the end, it still doesn't remove them. I've also tried adding them to a HashSet, but it still includes all the duplicates.
Anyone know of a reason why the duplicates might not be getting picked up?
Your DrivePairs class does not specify equality, as a result, the Contains method will be using reference equality. Add an Equals method that uses both Start and End to determine equality and you will probably find your code works.
See: Equality Comparisons (C# Programming Guide)
List.Contains Method
This method determines equality by using the default equality
comparer, as defined by the object's implementation of the
IEquatable.Equals method for T (the type of values in the list).
Change your DrivePairs class
public class DrivePairs: IEquatable<DrivePairs>
{
public int Start { get; set; }
public int End { get; set; }
public bool Equals(DrivePairs other)
{
return (this.Start == other.Start && this.End == other.End)
}
}
See: http://msdn.microsoft.com/en-us/library/bhkz42b3.aspx
Hope this helps
You are creating new List<int> objects - these are different objects and when compared to each other, even if they contain identical values (in the same or in different orders), will be evaluated as different as the default comparison method on reference types is a reference comparison.
You need to write a custom comparer that will identify equal lists in the manner your application requires.
I've marked Colin's as the answer, but here was the code just in case it's any use to anyone:
Equality comparer:
public class EqualityComparer : IEqualityComparer<DrivePairs>
{
public bool Equals(DrivePairs x, DrivePairs y)
{
return x.StartHub.Equals(y.Start);
}
public int GetHashCode(DrivePairs obj)
{
return obj.Start.GetHashCode();
}
}
and in the controller:
IEqualityComparer<DrivePairs> customComparer = new EqualityComparer();
IEnumerable<DrivePairs> distinctDrivePairs = drivePairs.Distinct(customComparer);
drivePairs = distinctDrivePairs.ToList();
Thanks for all the help and comments
I have not tested it but I think the default equality test is if it is the same instance. Try overriding the Equals method and make it use your properties.
The DrivePairs class type is a reference type(remember reference type and value type concept). So when you check if DrivePairs varible is already added in List collections or not it return false as every DrivePairs varibale has different memory location from other.
Try using either Dictionary or StringDictionary or any other Key value pair collection. It will definately work.

Categories