class Anime
{
public int Id { get; set; }
public string Title { get; set; }
public string ImageUrl { get; set; }
}
我有两个Anime类型的集合。我们假设他们称之为a1和a2。我想获得3个Anime类型的集合:
我怎样才能做到这一点?我想我应该对linq和Id值做些什么,但我没有找到适当的解决方案。 顺便说一下,Id值对于每个动画系列都是唯一的(如果两个项具有相同的Id,它们代表相同的系列)。
答案 0 :(得分:4)
如果您实施 GetHashCode 和 Equals 方法,您可以在链接的帮助下轻松编写代码。
class Anime
{
public int Id { get; set; }
public string Title { get; set; }
public string ImageUrl { get; set; }
public override int GetHashCode()
{
return Id.GetHashCode();
}
public override bool Equals(object obj)
{
var anime = obj as Anime;
if (anime == null) return false;
return this.Id == anime.Id;
}
}
现在可以按
完成var a1 = new List<Anime>()
{
new Anime() { Id=1, Title="Title1" },
new Anime() { Id=2, Title="Title2" },
new Anime() { Id=3, Title="Title3" },
new Anime() { Id=4, Title="Title4" }
};
var a2 = new List<Anime>()
{
new Anime() { Id=1, Title="Title1" },
new Anime() { Id=3, Title="Title3" },
new Anime() { Id=5, Title="Title5" }
};
var q1 = a1.Except(a2).ToList();
var q2 = a2.Except(a1).ToList();
var q3 = a1.Intersect(a2).ToList();
答案 1 :(得分:1)
这是一种简单的方法,它具有在LINQ over对象和LINQ over SQL上工作的额外好处:
var q1=a1.Where(a=>!a2.Any(b=>b.Id==a.Id));
var q2=a2.Where(a=>!a1.Any(b=>b.Id==a.Id));
var a3=a1.Where(a=>a2.Any(b=>b.Id==a.Id));
来自LINQPAD:
class Anime
{
public int Id { get; set; }
public string Title { get; set; }
public string ImageUrl { get; set; }
}
void Main()
{
var a1=new Anime[]{new Anime {Id=1,Title="Title1"},new Anime {Id=2,Title="Title2"}};
var a2=new Anime[]{new Anime {Id=2,Title="Title2"},new Anime {Id=3,Title="Title3"}};
var q1=a1.Where(a=>!a2.Any(b=>b.Id==a.Id));
var q2=a2.Where(a=>!a1.Any(b=>b.Id==a.Id));
var q3=a1.Where(a=>a2.Any(b=>b.Id==a.Id));
q1.Dump();
q2.Dump();
q3.Dump();
}
结果:
你也可以设置一个自定义的IEqualityComparer并使用Intersects,但除了高性能情况之外,它通常比它的价值更难,并且不能与LINQ over SQL一起使用:
class Anime
{
public int Id { get; set; }
public string Title { get; set; }
public string ImageUrl { get; set; }
}
class AnimeComparer: IEqualityComparer<Anime>
{
public bool Equals(Anime a1, Anime a2)
{
return (a1.Id==a2.Id);
}
public int GetHashCode(Anime a)
{
return a.Id.GetHashCode();
}
}
void Main()
{
var a1=new Anime[]{new Anime {Id=1,Title="Title1"},new Anime {Id=2,Title="Title2"}};
var a2=new Anime[]{new Anime {Id=2,Title="Title2"},new Anime {Id=3,Title="Title3"}};
var ac=new AnimeComparer();
var q1=a1.Except(a2,ac);
var q2=a2.Except(a1,ac);
var q3=a1.Intersect(a2,ac);
q1.Dump();
q2.Dump();
q3.Dump();
}
第三种方法是使用扩展方法。这也不太适用于LINQ over SQL,但是如果您有多种对象类型,则不需要修改任何类或自定义IEqualityComparers:
public static class LinqExtensions
{
public static IEnumerable<TSource> Except<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second, Func<TSource, TSource, bool> comparer)
{
return first.Where(x => !second.Any(y => comparer(x, y)));
}
public static IEnumerable<TSource> Intersect<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second, Func<TSource, TSource, bool> comparer)
{
return first.Where(x => second.Any(y => comparer(x, y)));
}
}
class Anime
{
public int Id { get; set; }
public string Title { get; set; }
public string ImageUrl { get; set; }
}
void Main()
{
var a1=new Anime[]{new Anime {Id=1,Title="Title1"},new Anime {Id=2,Title="Title2"}};
var a2=new Anime[]{new Anime {Id=2,Title="Title2"},new Anime {Id=3,Title="Title3"}};
var q1=a1.Except(a2,(b1,b2)=>b1.Id==b2.Id);
var q2=a2.Except(a1,(b1,b2)=>b1.Id==b2.Id);
var q3=a1.Intersect(a2,(b1,b2)=>b1.Id==b2.Id);
q1.Dump();
q2.Dump();
q3.Dump();
}
第四个选项是使用morelinq,它结合了没有自定义IEqualityComparers的简单性和非常高的性能(但仍然不兼容LINQ over SQL):
class Anime
{
public int Id { get; set; }
public string Title { get; set; }
public string ImageUrl { get; set; }
}
void Main()
{
var a1=new Anime[]{new Anime {Id=1,Title="Title1"},new Anime {Id=2,Title="Title2"}};
var a2=new Anime[]{new Anime {Id=2,Title="Title2"},new Anime {Id=3,Title="Title3"}};
var q1=a1.ExceptBy(a2,k=>k.Id);
var q2=a2.ExceptBy(a1,k=>k.Id);
var q3=a1.ExceptBy(q1,k=>k.Id);
q1.Dump();
q2.Dump();
q3.Dump();
}