如何正确转换集合?

时间:2015-08-03 15:56:44

标签: c# .net linq windows-runtime

class Anime
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string ImageUrl { get; set; }
}

我有两个Anime类型的集合。我们假设他们称之为a1和a2。我想获得3个Anime类型的集合:

  1. 仅在a1
  2. 中的项目
  3. 仅在a2
  4. 中的项目
  5. 两个集合中的项目
  6. 我怎样才能做到这一点?我想我应该对linq和Id值做些什么,但我没有找到适当的解决方案。 顺便说一下,Id值对于每个动画系列都是唯一的(如果两个项具有相同的Id,它们代表相同的系列)。

2 个答案:

答案 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();
}

结果:

enter image description here

你也可以设置一个自定义的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();
}