Сравнить списки для получения свойств объекта, которые не соответствуют

Я использую этот запрос linq (успешно в большинстве случаев), чтобы проверить один список на другой список. Цель состоит в том, чтобы вернуть объекты, у которых ThresholdType не включен в список validThresholds.

// Filter out thresholds previously added
manufacturerResult = (from r in validThresholds
 from t in manufacturerLevel
 where r.ThresholdType != t.ThresholdType
 select t).ToList();

По какой-то причине, которая меня действительно сбивает с толку, я получаю результат из 20 объектов. Из сравнения списка возможных 9 объектов с списком из 3 действительных объектов. Очевидно, что я сделал некоторые ошибки в логике здесь, но я не вижу, как я мог бы получить больше результатов, чем сумма обеих коллекций! Мне действительно интересно узнать, почему я получаю этот результат.

Первоначально я хотел использовать Join но это ограничивает меня, поскольку он допускает только equals без оператора неравенства.

Ниже я создал образец приложения, которое воссоздает проблему.

public class ConsumableThreshold
{
 public int ThresholdType { get; set; }
 public int ThresholdValue { get; set; }

 public int ConsumableType { get; set; }
 public int ConsumableVariantID { get; set; }
 public int ManufacturerID { get; set; }
 public int ModelID { get; set; }

}
public partial class Form1 : Form
{
 public Form1()
 {
 InitializeComponent();

 DoWork();
 }

 private void DoWork()
 {
 try
 {
 int manufacturerID = 4;


 ConsumableThreshold t1 = new ConsumableThreshold()
 {
 ConsumableType = 0,
 ConsumableVariantID = 0,
 ManufacturerID = 4,
 ModelID = 0,
 ThresholdType = 3,
 ThresholdValue = 30
 };
 ConsumableThreshold t2 = new ConsumableThreshold()
 {
 ConsumableType = 0,
 ConsumableVariantID = 0,
 ManufacturerID = 4,
 ModelID = 0,
 ThresholdType = 2,
 ThresholdValue = 50000
 };
 ConsumableThreshold t3 = new ConsumableThreshold()
 {
 ConsumableType = 0,
 ConsumableVariantID = 0,
 ManufacturerID = 4,
 ModelID = 0,
 ThresholdType = 6,
 ThresholdValue = 3
 };
 ConsumableThreshold t4 = new ConsumableThreshold()
 {
 ConsumableType = 0,
 ConsumableVariantID = 2058,
 ManufacturerID = 4,
 ModelID = 123,
 ThresholdType = 3,
 ThresholdValue = 31
 };
 ConsumableThreshold t5 = new ConsumableThreshold()
 {
 ConsumableType = 3,
 ConsumableVariantID = 0,
 ManufacturerID = 4,
 ModelID = 0,
 ThresholdType = 3,
 ThresholdValue = 99
 };
 ConsumableThreshold t6 = new ConsumableThreshold()
 {
 ConsumableType = 0,
 ConsumableVariantID = 0,
 ManufacturerID = 4,
 ModelID = 123,
 ThresholdType = 3,
 ThresholdValue = 25
 };
 ConsumableThreshold t7 = new ConsumableThreshold()
 {
 ConsumableType = 0,
 ConsumableVariantID = 0,
 ManufacturerID = 4,
 ModelID = 123,
 ThresholdType = 1,
 ThresholdValue = 10
 };
 ConsumableThreshold t8 = new ConsumableThreshold()
 {
 ConsumableType = 0,
 ConsumableVariantID = 0,
 ManufacturerID = 4,
 ModelID = 123,
 ThresholdType = 4,
 ThresholdValue = 15
 };
 ConsumableThreshold t9 = new ConsumableThreshold()
 {
 ConsumableType = 3,
 ConsumableVariantID = 0,
 ManufacturerID = 0,
 ModelID = 0,
 ThresholdType = 3,
 ThresholdValue = 1
 };
 ConsumableThreshold t10 = new ConsumableThreshold()
 {
 ConsumableType = 2057,
 ConsumableVariantID = 0,
 ManufacturerID = 4,
 ModelID = 123,
 ThresholdType = 3,
 ThresholdValue = 32
 };


 List<consumablethreshold> groupThresholds = new List<consumablethreshold>()
 {
 t1,t2,t3,t4,t5,t6,t7,t8,t9,t10
 };

 List<consumablethreshold> validThresholds = new List<consumablethreshold>()
 {
 t5, t7, t8
 };

 List<consumablethreshold> manufacturerLevel =
 (from t in groupThresholds
 where t.ManufacturerID != 0 && t.ManufacturerID == manufacturerID
 select t).ToList();

 if (manufacturerLevel.Count > 0)
 {
 List<consumablethreshold> manufacturerResult = new List<consumablethreshold>();

 if (validThresholds.Count > 0)
 {
 // Filter out thresholds previously added
 manufacturerResult = (from r in validThresholds
 from t in manufacturerLevel
 where r.ThresholdType != t.ThresholdType
 select t).ToList();
 }
 else
 {
 manufacturerResult = manufacturerLevel;
 }

 validThresholds.AddRange(manufacturerResult);
 }
 }
 catch (Exception)
 {

 throw;
 }
 }
}
</consumablethreshold></consumablethreshold></consumablethreshold></consumablethreshold></consumablethreshold></consumablethreshold></consumablethreshold>

Как я могу правильно сравнить два списка и вернуть объекты, где определенное значение свойства не существует в другом?

3 ответа

Как я могу правильно сравнить два списка и вернуть объекты, где определенное значение свойства не существует в другом?

Что-то вроде этого?

manufacturerResult = (from t in manufacturerLevel
 // where a specific property value does not exist in the other
 where !validThresholds.Any(
 r => r.ThresholdType == t.ThresholdType)
 select t).ToList();

Мое намерение состоит в том, чтобы добавить объекты от производителяLevel к validThresholds, где любой объект в validThreshold не имеет того же значения ThresholdType, что и любой объект в factoryLevel

validThresholds.AddRange(
 manufacturerLevel.Where(t => !validThresholds.Any(
 r => r.ThresholdType == t.ThresholdType)));

Вы также можете подумать о том, что именно вы пытаетесь сделать, это скомпилировать Set этих объектов. Если вы сделали validThresholds HashSet<>, например, с IEqualityComparer<> на основе ThresholdType, вы могли бы просто Add все элементы и автоматически игнорировать любые, чей ThresholdType уже был представлен в коллекции.


Вы можете сделать это следующим образом:

var result = manufacturerLevel.Where(t => !validThresholds.Any(t2 => t.ThresholdType == t2.ThresholdType));

РЕДАКТИРОВАТЬ:

Мое намерение состоит в том, чтобы добавить объекты от производителяLevel к validThresholds, где любой объект в validThreshold не имеет того же значения ThresholdType, что и любой объект в factoryLevel

Если бы я понял это правильно, вам нужно объединить две коллекции, верно?

var validThresholds= validThresholds.Union(manufacturerLevel);

Убедитесь, что вы правильно переопределили метод Equals в ConsumableThreshold


Вы также можете сделать это, у вас может быть свой пользовательский сопоставитель, чтобы определить, отличается ли объект от другого, а затем просто использовать. Кроме сбора этих объектов.

public class ConsumableThreshold : IEqualityComparer<consumablethreshold>
 {
 public int ThresholdType { get; set; }
 public int ThresholdValue { get; set; }

 public int ConsumableType { get; set; }
 public int ConsumableVariantID { get; set; }
 public int ManufacturerID { get; set; }
 public int ModelID { get; set; }

 public bool Equals(ConsumableThreshold x, ConsumableThreshold y)
 {
 return x.ThresholdType == y.ThresholdType;
 }

 public int GetHashCode(ConsumableThreshold obj)
 {
 return obj.ThresholdType.GetHashCode();
 }
 }
</consumablethreshold>

И тогда получится такая разница:

var diff = groupThresholds.Except(validThresholds).ToList();

licensed under cc by-sa 3.0 with attribution.