I have data with the following shape
someArray = [{ Name: "Some Class", TypeEnum: "Default" },
{ Name: "Some Class", TypeEnum: "Other" },
{ Name: "Some Class 2", TypeEnum: "Default" },
{ Name: "Some Class 2", TypeEnum: "Other" },
{ Name: "Some Class 3", TypeEnum: "Default" },
{ Name: "Some Class 4", TypeEnum: "Not Other" }]
Imagine each of those as objects in C#
What I need is an array of distinct versions of that array, with preference given to a selected TypeEnum. For example if I have selected the TypeEnum of other, I still want it to default to Default if it can't find a version of that class with the "Other" TypeEnum
e.g. With "Other" selected as the Type enum, the above data would look like
[{ Name: "Some Class", TypeEnum: "Other" },
{ Name: "Some Class 2", TypeEnum: "Other" },
{ Name: "Some Class 3", TypeEnum: "Default" }]
What I'm doing now is a lambda comparison from here
TypeEnum myEnum = "Other"
someArray.Distinct((x,y) => x.Name == y.Name &&
x.TypeEnum != myEnum &&
(y.TypeEnum == myEnum || y.TypeEnum == "Default"));
I'm hoping that Distinct pops out any x from the array that get's a true from that expression.
Am I wrong in how I think Distinct works. If I am, what should I use instead?
You can define a Comparer<T> class to handle your preference for comparison, like this:
public class SomeClassComparer : Comparer<SomeClass>
{
private TypeEnum _preference;
public SomeClassComparer(TypeEnum preference)
: base()
{
_preference = preference;
}
public override int Compare(SomeClass x, SomeClass y)
{
if (x.Name.Equals(y.Name))
{
return x.TypeEnum == y.TypeEnum ? 0
: x.TypeEnum == _preference ? -1
: y.TypeEnum == _preference ? 1
: x.TypeEnum == TypeEnum.Default ? -1
: y.TypeEnum == TypeEnum.Default ? 1
: x.TypeEnum.CompareTo(y.TypeEnum);
}
else
return x.Name.CompareTo(y.Name);
}
}
UPDATE:
If you're only interested in the elements with your preferred or Default TypeEnum, you could filter out the rest first. Then sort the array according to the Comparer, i.e. giving preferred TypeEnum higher precedence than Default. Finally group the objects by their Name, and take the first one from each group:
var result = someArray.Where(x => x.TypeEnum == TypeEnum.Default || x.TypeEnum == myEnum)
.OrderBy(x => x, new SomeClassComparer(myEnum))
.GroupBy(x => x.Name)
.Select(x => x.First());
Or you can use the following version if you don't want to define a Comparer class:
Comparison<SomeClass> compareByTypeEnum = (x, y) =>
{
if (x.Name.Equals(y.Name))
{
return x.TypeEnum == y.TypeEnum ? 0
: x.TypeEnum == myEnum ? -1
: y.TypeEnum == myEnum ? 1
: x.TypeEnum == TypeEnum.Default ? -1
: y.TypeEnum == TypeEnum.Default ? 1
: x.TypeEnum.CompareTo(y.TypeEnum);
}
else
return x.Name.CompareTo(y.Name);
};
Array.Sort(someArray, compareByTypeEnum);
var result = someArray.Where(x => x.TypeEnum == TypeEnum.Default || x.TypeEnum == TypeEnum.Other)
.GroupBy(x => x.Name)
.Select(x => x.First());
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With