You wrote:
items have different taxes, but mostly items have the same taxes
The most important thing for you to do is to define when two taxes are equal. Is it when they have equal TaxId
and TaxValue
, or is it when they have the same TaxValue
, or should it be the same object. So which of these five Taxes are equal:
Taxes a = new Taxes {Taxid = 1, TaxValue = 3};
Taxes b = new Taxes {Taxid = 1, TaxValue = 4};
Taxes c = new Taxes {Taxid = 2, TaxValue = 4};
Taxes d = new Taxes {Taxid = 2, TaxValue = 4};
Taxes e = d;
If your answer would be: it depends: sometimes only d == e (same object), sometimes b == c == d == e (equal TaxValue), then you should provide an equality comparer: an object that implements IEqualityComparer<Taxes>
.
Usually the answer is not so difficult, I think you want to say that two Taxes are equal if they have equal TaxValue
So your requirements are as follows:
- Input: a sequence of OrderDetails. Every OrderDetail has a DetailId and a sequence of zero or more Taxes. Every Tax has a TaxId and a TaxValue.
- Two Taxes are considered equal if they have the same TaxValue.
- Requested output: From every OrderDetail the DetailId and a sequence of all its unique Taxes.
To select properties of input items use Enumerable.Select To keep only the Unique output values of a sequence use Enumerable.Distinct
var result = myOrderDetails // take my sequence of OrderDetails
.Select(orderDetail => new // from every orderDetail in this sequence make one new object
{ // with the following properties
DetailId = orderDetail.DetailId,
TaxValues = orderDetail.Taxes // from all Taxes of this orderDetail,
.Select(tax => tax.TaxValue) // select only the TaxValues
.Distinct(), // and remove duplicates
// or if two taxValues are equal if they are the same object:
Taxes = orderDatail.Taxes // from all Taxes of this orderDetail
.Distinct() // remove duplicates
.Select(tax => tax.TaxValue), // and keep only the TaxValue (optional)
});
If your idea about equality of Taxes is not is not that simple, for instance if you would define equality as:
Two taxes are equal if they have equal TaxId, and equal TaxValue
In that case you'll have to write an equality comparer. They are not very difficult, however you should keep something in mind:
- What to do with a Null-value? If both are null, are they equal?
- Keep in mind that a derived class of a TaxValue is usually not equal to the TaxValue itself
Consider reading Define Value Equality for a Type
class TaxesEqualityComparer : EqualityComparer<TaxValue>
{
public static readonly IEqualityComparer<TaxValue> ValueComparer
= new TaxesEqualityComparer()
public override bool Equals(TaxValue x, TaxValue y)
{
// the following lines are almost always the same:
if (x == null) return y == null; // true if both null
if (y != null) return false; // because x not null and y is null
if (Object.ReferenceEquals(x, y) return true; // optimalization: same object
// no need to check the properties
if (x.GetType() != y.GetType()) return false; // not same type
// here start the differences of default Taxes comparison
// when would you say that two Taxes are equal?
return x.TaxId == y.TaxId
&& x.TaxValue == y.TaxValue;
};
public override int GetHashCode(x)
{
...
}
}
The GetHashCode is an optimization used by classes like Dictionaries, Sets, and functions like Distinct() to quickly find inequalities. There is no "best" way to define this function. Stack overflow: Best algorithm for GetHashCode might help you.
Once you've defined the class, you can use the equalicy comparer in Distinct:
// use default equality (= equal if same object)
...
.Distinct(TaxesEqualityComparer.Default)
// use your own definition of Taxes equality:
...
.Distinct(TaxesEqualityComparer.ValueComparer)