2015-08-03 3 views
-3
class Anime 
{ 
    public int Id { get; set; } 
    public string Title { get; set; } 
    public string ImageUrl { get; set; } 
} 

У меня есть две коллекции типа Аниме. Предположим, они назвали a1 и a2. Я хочу, чтобы получить 3 коллекции типа Анима:Как правильно преобразовать коллекции?

  1. пунктов, которые только в a1
  2. товаров, которые только в а2
  3. Элементов, которые находятся в обеих коллекциях

Как можно достичь это? Я думаю, что я должен что-то сделать с linq и значением Id, но мне не удалось найти адекватное решение. Кстати, значение Id уникально для каждой серии аниме (если два элемента имеют одинаковый идентификатор, они представляют одну и ту же серию).

+3

См 'IEnumerable ' методы, такие как Intersect, за исключением, Союза – EZI

+0

и создать 'IComparer' для' Anime' типа. –

ответ

4

Если вы реализуете GetHashCode и Равно метода, вы можете легко написать код Wi th помощь ссылки.

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(); 
+0

И если вы не можете по какой-то причине реализовать эти методы для самого объекта, вы можете создать класс, который реализует 'IEqualityComparer', а затем вызвать перегрузки' Except' и 'Intersect', которые принимают параметр' IEqualityComparer'. –

1

Это простой способ сделать это, который имеет дополнительное преимущество работы как в LINQ над объектами и LINQ над 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

Вы также можете настроить пользовательский IEqualityComp ARER и использовать пересекающей, но это, как правило, гораздо сложнее, чем это стоит во всех, кроме высокой производительности ситуациях, и не работает с LINQ над 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 над 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 над 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(); 
} 
+0

Спасибо за проголосовать без объяснений, но приведенный выше код работает просто отлично. –

Смежные вопросы