我有以下形状的数据
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" }]
想象一下这些作为C#
中的对象我需要的是该数组的不同版本的数组,优先选择TypeEnum。例如,如果我选择了其他的TypeEnum,我仍然希望它默认为默认,如果它找不到具有“其他”TypeEnum的该类的版本
e.g。选择“其他”作为类型枚举,上面的数据看起来像
[{ Name: "Some Class", TypeEnum: "Other" },
{ Name: "Some Class 2", TypeEnum: "Other" },
{ Name: "Some Class 3", TypeEnum: "Default" }]
我现在正在做的是来自here
的lambda比较TypeEnum myEnum = "Other"
someArray.Distinct((x,y) => x.Name == y.Name &&
x.TypeEnum != myEnum &&
(y.TypeEnum == myEnum || y.TypeEnum == "Default"));
我希望Distinct从数组中弹出任何从该表达式得到的x。
我认为Distinct的工作原理是错误的。如果我是,我应该使用什么呢?
答案 0 :(得分:2)
您可以定义Comparer<T>
类来处理您的偏好以进行比较,如下所示:
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);
}
}
更新:
如果您只对首选或默认TypeEnum
的元素感兴趣,可以先将其余元素过滤掉。然后根据Comparer对数组进行排序,即优先TypeEnum
优先于Default。最后按名称对对象进行分组,并从每个组中取出第一个:
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());
如果您不想定义Comparer类,则可以使用以下版本:
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());
答案 1 :(得分:1)
您可以使用GroupBy获取字典来完成此类工作。可能它也简单得多。
List<Tuple<string, string>> lst = new List<Tuple<string, string>>();
lst.Add(new Tuple<string, string>("Some Class", "Default"));
lst.Add(new Tuple<string, string>("Some Class", "Other"));
lst.Add(new Tuple<string, string>("Some Class 2", "Default"));
lst.Add(new Tuple<string, string>("Some Class 2", "Other"));
lst.Add(new Tuple<string, string>("Some Class 3", "Default"));
var dict = lst.GroupBy(g => g.Item1)
.ToDictionary(g => g.Key, k => k.Select(s => s.Item2)
.Where(p => p == "Other")
.DefaultIfEmpty("Default")
.First());
或者在你的情况下:
TypeEnum myEnum = "Other"
var dict = lst.GroupBy(g => g.Name)
.ToDictionary(g => g.Key, k => k.Select(s => s.TypeEnum)
.Where(p => p == myEnum)
.DefaultIfEmpty("Default")
.First());
答案 2 :(得分:1)
区别不按您想要的方式工作,这就是为什么您可能永远无法单独使用它。不同的是使用哈希表来查找唯一值。它按顺序将每个项添加到哈希表中,并省略添加哈希值等于哈希表中已有的任何其他值的任何值。
这意味着项目的顺序很重要,因为数组中的第一项获胜。我们可以通过在调用distinct之前修改对列表的排序来使用它。稍微修改@ Fung的solution我们得到这个......
var result = someArray.OrderBy(key => key.TypeEnum, new TypeEnumComparer(myEnum))
.Distinct(new LambdaEqualityComparer<SomeClass>((x, y) => x.Name == y.Name));
使用经过修改的比较器...
public class TypeEnumComparer : Comparer<TypeEnum>
{
private TypeEnum _preference;
public TypeEnumComparer(TypeEnum preference)
: base()
{
_preference = preference;
}
public override int Compare(TypeEnum x, TypeEnum y)
{
if (x == y) return 0;
if (x == _preference) return -1;
if (y == _preference) return 1;
if (x == TypeEnum.Default) return -1;
if (y == TypeEnum.Default) return 1;
return x.CompareTo(y);
}
}
答案 3 :(得分:0)
试试这个,使用DefaultIfEmpty("Default")
var someArray = new List<TestClass>
{
new TestClass {Name = "Some Class", TypeEnum = "Default"},
new TestClass {Name = "Some Class", TypeEnum = "Other"},
new TestClass {Name = "Some Class 2", TypeEnum = "Default"},
new TestClass {Name = "Some Class 2", TypeEnum = "Other"},
new TestClass {Name = "Some Class 3", TypeEnum = "Default"}
};
string myEnum = "Other";
var result = someArray.GroupBy(t => t.Name).
Select(t => new TestClass
{
Name = t.Key,
TypeEnum = t.Select(s => s.TypeEnum).Where(p => p == myEnum).DefaultIfEmpty("Default").FirstOrDefault()
});