C # Linq пересекается / за исключением одной части объекта

20

Я осмотрелся и не могу найти ничего, чтобы помочь здесь. У меня класс:

class ThisClass
{
  private string a {get; set;}
  private string b {get; set;}
}

Я хотел бы использовать методы Intersect и Except Linq, т. е.

private List<ThisClass> foo = new List<ThisClass>();
private List<ThisClass> bar = new List<ThisClass>();

Затем я заполняю два списка отдельно. Я хотел бы сделать, например (и я знаю, что это неправильно, просто псевдокод), следующее:

foo[a].Intersect(bar[a]);

Как мне это сделать?

Спасибо за любую помощь:)

    
задан David Archer 17.05.2012 в 11:51
источник
  • Что вам нужно? Объясните словами, что вы хотите от этой строки foo [a] .Intersect (bar [a]) ;. –  Nikhil Agrawal 17.05.2012 в 11:59

7 ответов

26

Может

// returns list of intersecting property 'a' values
foo.Select(f => f.a).Intersect(bar.Select(b => b.a));

Свойство BTW a должно быть общедоступным.

    
ответ дан Sergey Berezovskiy 17.05.2012 в 11:54
источник
  • Ницца, просто, делает то, что мне нужно. Спасибо вам и всем ответчикам. –  David Archer 17.05.2012 в 12:15
19

Если вам нужен список одного свойства, которое вы хотели бы пересечь, тогда все остальные красивые решения LINQ работают нормально. НО! Если вы хотите пересечься по всему классу, и в результате получится List<ThisClass> вместо List<string> , вам придется написать свой собственный сравнительный анализатор.

foo.Intersect(bar, new YourEqualityComparer());

то же самое с Except .

public class YourEqualityComparer: IEqualityComparer<ThisClass>
{

    #region IEqualityComparer<ThisClass> Members


    public bool Equals(ThisClass x, ThisClass y)
    {
        //no null check here, you might want to do that, or correct that to compare just one part of your object
        return x.a == y.a && x.b == y.b;
    }


    public int GetHashCode(ThisClass obj)
    {
        unchecked
        {
            var hash = 17;
                            //same here, if you only want to get a hashcode on a, remove the line with b
            hash = hash * 23 + obj.a.GetHashCode();
            hash = hash * 23 + obj.b.GetHashCode();

            return hash;    
        }
    }

    #endregion
}
    
ответ дан Patryk Ćwiek 17.05.2012 в 12:00
источник
3

Не уверен в скорости этого по сравнению с пересечением и сравнением, но как насчет:

//Intersect
var inter = foo.Where(f => bar.Any(b => b.a == f.a));
//Except - values of foo not in bar
var except = foo.Where(f => !bar.Any(b => b.a == f.a));
    
ответ дан Zach Johnson 14.01.2015 в 19:05
источник
  • Это алгоритм O (n * m), тогда как Intersect и Exception оба являются O (n + m). Это делает вас намного хуже. Он также выполняет многократную повторную проверку, что может быть серьезной проблемой во всех ситуациях (она может не давать одинаковых результатов на каждой итерации, она может запрашивать базу данных или преформировать дорогостоящие вычисления на каждой итерации, она может иметь побочные эффекты, вызванные итерации и т. д. –  Servy 14.01.2015 в 19:07
2
foo.Select(x=>x.a).Intersect(bar.Select(x=>x.a))
    
ответ дан Tilak 17.05.2012 в 11:55
источник
0

Что такое желаемый эффект? Вы хотите получить список строк, состоящий из всех a в ваших классах, или список ThisClass , когда два экземпляра ThisClass идентифицируются с помощью уникальных значений a ?

Если это первый, два ответа от @lazyberezovksy и @Tilak должны работать. Если это последнее, вам придется переопределить IEqualityComparer<ThisClass> или IEquatable<ThisClass> , так что Intersect знает, что делает два экземпляра ThisClass равнозначным:

 private class ThisClass : IEquatable<ThisClass>
 {
     private string a;

     public bool Equals(ThisClass other)
     {
        return string.Equals(this.a, other.a);
     }
 }

, то вы можете просто позвонить:

 var intersection = foo.Intersect(bar);     
    
ответ дан Avner Shahar-Kashtan 17.05.2012 в 12:02
источник
  • Вы всегда должны переопределять GetHashCode при реализации IEquatable. Поскольку вы этого не сделаете, это не сработает. –  Servy 14.01.2015 в 19:09
0

Я знаю, что это старо, но не могли бы вы просто переопределить Equals & amp; GetHashCode в самом классе?

class ThisClass
{
  public string a {get; set;}
  private string b {get; set;}

  public override bool Equals(object obj)
  {
    // If you only want to compare on a
    ThisClass that = (ThisClass)obj;
    return string.Equals(a, that.a/* optional: not case sensitive? */);
  }

  public override int GetHashCode()
  {
    return a.GetHashCode();
  }
}
    
ответ дан tyr 10.11.2016 в 20:44
источник
-2

Вы должны создать IEqualityComparer. Вы можете передать метод IEqualityComparer в метод Intersect (). Это поможет вам легче получить список (который пересекает панель).

var intersectionList = foo.Intersect(bar, new ThisClassEqualityComparer()).ToList();


class ThisClassEqualityComparer : IEqualityComparer<ThisClass>
{

    public bool Equals(ThisClass b1, ThisClass b2)
    {
        return b1.a == b2.a;
    }


    public int GetHashCode(Box bx)
    {
       // To ignore to compare hashcode, please consider this.
       // I would like to force Equals() to be called
       return 0;
    }

}
    
ответ дан Pongsathon.keng 17.05.2012 в 12:01
источник
  • Вы не должны возвращать 0 из хэш-кода, подобного этому. Это полностью уничтожит производительность. Вместо этого вы должны использовать хеш-код a. –  Servy 14.01.2015 в 19:08