Linq Contains - не работает для подобъекта [duplicate]

В ответ на Is there a specific reason? здесь представлено одно интересное приложение: разрыв нескольких уровней цикла.

Вот как это работает: внешний контур имеет разрыв в конце, поэтому он будет выполняется только один раз. Однако, если внутренний цикл завершает (не находит делителя), он достигает выражения else, и внешний разрыв никогда не достигается. Таким образом, разрыв во внутреннем цикле будет выходить из обеих петель, а не только из одного.

for k in [2, 3, 5, 7, 11, 13, 17, 25]:
    for m in range(2, 10):
        if k == m:
            continue
        print 'trying %s %% %s' % (k, m)
        if k % m == 0:
            print 'found a divisor: %d %% %d; breaking out of loop' % (k, m)
            break
    else:
        continue
    print 'breaking another level of loop'
    break
else:
    print 'no divisor could be found!'

Для циклов while и for оператор else выполняется в конец, если не было использовано break.

В большинстве случаев есть лучшие способы сделать это (обертывание его в функцию или создание исключения), но это работает!

69
задан David 6 January 2016 в 23:23
поделиться

5 ответов

Вам нужно реализовать IEquatable или переопределить Equals() и GetHashCode()

Например:

public class CartProduct : IEquatable<CartProduct>
{
    public Int32 ID;
    public String Name;
    public Int32 Number;
    public Decimal CurrentPrice;

    public CartProduct(Int32 ID, String Name, Int32 Number, Decimal CurrentPrice)
    {
        this.ID = ID;
        this.Name = Name;
        this.Number = Number;
        this.CurrentPrice = CurrentPrice;
    }

    public String ToString()
    {
        return Name;
    }

    public bool Equals( CartProduct other )
    {
        // Would still want to check for null etc. first.
        return this.ID == other.ID && 
               this.Name == other.Name && 
               this.Number == other.Number && 
               this.CurrentPrice == other.CurrentPrice;
    }
}
95
ответ дан Rowland Shaw 18 August 2018 в 22:26
поделиться

Если вы хотите иметь контроль над этим, вам нужно реализовать [IEquatable interface] [1]

[1]: http: // Этот метод определяет равенство по используя сопоставитель равенства по умолчанию, как определено реализацией объекта метода IEquatable.Equals для T (тип значений в списке).

0
ответ дан Gerrie Schenck 18 August 2018 в 22:26
поделиться

Он проверяет, содержится ли конкретный объект в списке.

Возможно, вам лучше использовать метод Find в списке.

Вот пример

List<CartProduct> lst = new List<CartProduct>();

CartProduct objBeer;
objBeer = lst.Find(x => (x.Name == "Beer"));

Надеюсь, что поможет

Вы также должны посмотреть на LinQ - overkill для этого, возможно, но полезный инструмент, тем не менее ...

10
ответ дан Martin Milan 18 August 2018 в 22:26
поделиться
  • 1
    как Linq когда-либо может быть излишним? – Mel Gerats 13 April 2010 в 13:25
  • 2
    @MEL - Зачем смешивать в запросе и вводить вывод для чего-то такого простого? Тем не менее, это может быть более читаемым для кого-то, не знакомого с ламдой ... – Martin Milan 13 April 2010 в 14:15
  • 3
    +1 Хороший пример, который показывает вариант, на который не повлияли бы изменения в другом месте (т. Е. Если метод Equals() был изменен по любой причине) – Rowland Shaw 13 April 2010 в 16:18

Если вы используете .NET 3.5 или новее, вы можете использовать методы расширения LINQ для достижения проверки «содержит» с помощью метода расширения Any :

if(CartProducts.Any(prod => prod.ID == p.ID))

Это проверит наличие продукта внутри CartProducts, который имеет идентификатор, соответствующий ID p. Вы можете поместить любое логическое выражение после => для выполнения проверки.

Это также имеет преимущество для работы с запросами LINQ-SQL, а также с запросами в памяти, где Contains нет.

102
ответ дан Paul Turner 18 August 2018 в 22:26
поделиться

По умолчанию ссылочные типы имеют ссылочное равенство (т. е. два экземпляра равны только, если они являются одним и тем же объектом).

Вам необходимо переопределить Object.EqualsObject.GetHashCode для соответствия), чтобы реализовать ваши собственное равенство. (И тогда хорошей практикой является реализация равенства, ==, operator.)

5
ответ дан Richard 18 August 2018 в 22:26
поделиться
  • 1
    Зачем перекрывать Object.Equals, которые могут иметь последствия в другом месте кода? Для меня имеет смысл изменить соответствующий код поиска, а не базовый класс объекта, который выполняется поиск ... – Martin Milan 13 April 2010 в 12:45
  • 2
    У вас есть примеры этого, .Find () или переопределить Object.Equals / GetHashCode? – Jan Johansen 13 April 2010 в 12:49
  • 3
    @Martin IT будет очень сломан, если вы хотите, чтобы сравнение двух CartProduct объектов велось по-разному в разных местах. – Rowland Shaw 13 April 2010 в 12:51
  • 4
    @Rowland - Но я не говорю, что он должен будет изменить, как работает сравнение. Если ему нужен конкретный объект, используйте Contains (). Если он хочет, чтобы какой-либо объект соответствовал указанным критериям, используйте Find () с подходящим предикатом (выражение lamda) ... Я на самом деле утверждаю, что вы не касаетесь кода сравнения AT ALL - вы просто вызываете правильный метод на список задач, которые вы пытаетесь выполнить ... – Martin Milan 13 April 2010 в 13:01
  • 5
    @Martin Появляется, что я неверно истолковал ваш комментарий как нечто вроде строк «переопределить Contains()». Согласитесь, что Find() может решить проблему, хотя я бы предположил, что подходящий метод equals может быть более полезным в нагрузках других случаев, поскольку OP не заметил, что ссылки для двух экземпляров одного и того же объекта были разными. – Rowland Shaw 13 April 2010 в 13:06
Другие вопросы по тегам:

Похожие вопросы: