-3

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?

Manfred Radlwimmer
  • 13,257
  • 13
  • 53
  • 62
Diego Slinger
  • 139
  • 11
  • 1
    Override the equals method of the assetrecord function to check if the two fields inside match...that should work – Ctznkane525 Jan 01 '18 at 22:36
  • You need to define equality for your type (https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/how-to-define-value-equality-for-a-type), or use a custom `IEqualityComparer` in the overload of `Enumerable.Intersect` that takes two paramters (https://msdn.microsoft.com/en-us/library/bb355408(v=vs.110).aspx). – Preston Guillot Jan 01 '18 at 22:38
  • ... or implement an IEqualityComparer and use the overload of Intersect – Sir Rufo Jan 01 '18 at 22:38
  • @JohnKane how do i do that? And how should i use Equals method in the Intersect? – Diego Slinger Jan 01 '18 at 22:39
  • 1
    @DiegoSlinger Read the docs. It is well documented and there are countless samples on the web – Sir Rufo Jan 01 '18 at 22:39
  • 1
    `Intersect` calls `Equals` itself in the overload you're using, you just need to implement it. If you _don't_ want to define equality on your type, you need to implement an `IEqualityComparer` and pass an instance of it to `Intersect`. – Preston Guillot Jan 01 '18 at 22:40
  • @SirRufo Thx Cap! Good advise - google your problem... – Diego Slinger Jan 01 '18 at 22:50
  • If you use a tuple with two fields instead of a custom class ..or an inherited tuple all this is done automatically – Ctznkane525 Jan 02 '18 at 21:06

1 Answers1

2

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:

  1. Prices should be a decimal, not a double. You want exact decimal values, use the right tool provided by the framework.
  2. 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.
Preston Guillot
  • 6,493
  • 3
  • 30
  • 40
InBetween
  • 32,319
  • 3
  • 50
  • 90