dimanche 11 mai 2014

c# - Compare répertorie pour récupérer les propriétés de l'objet qui ne correspondent pas - Stack Overflow


I'm using this linq query (successfully in most instances) to check one List against another List. The objective is to return the objects which have a ThresholdType not already included in the validThresholds list.


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

For some reason, which is really confusing me, I am getting a result of 20 objects. From comparing a list of possible 9 objects against a list of 3 valid objects. Obviously I have made some error in the logic here, but I cannot see how I could get more results back than the sum of both collections! I am really interested to know why I am getting this result.


Originally I wanted to use a Join but that restricts me as it only allows the equals with no inequality operator.


Below I have created a sample application which recreates the issue.


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;
}
}
}

How can I correctly compare two lists and return the objects where a specific property value does not exist in the other?





How can I correctly compare two lists and return the objects where a specific property value does not exist in the other?



Something like this?


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


My intent is to add the objects from manufacturerLevel to validThresholds where any object in validThreshold doesn't have the same ThresholdType value as any object in manufacturerLevel



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

You may also want to consider whether what you're really trying to do is compile a Set of these objects. If you made validThresholds a HashSet<>, for example, with an IEqualityComparer<> based on the ThresholdType, you could simply Add all the items, and it would automatically ignore any whose ThresholdType was already represented in the collection.




You can do it like this:


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

EDIT:



My intent is to add the objects from manufacturerLevel to validThresholds where any object in validThreshold doesn't have the same ThresholdType value as any object in manufacturerLevel



If I understood it correctliy you need to merge the two collections, right?


var validThresholds= validThresholds.Union(manufacturerLevel);

Make sure you override properly the Equalsmethod in ConsumableThreshold




There is a big difference between join and two from operators. You query gives you all combinations of both lists minus those where threshold is not different. Your t will be repeated many times. What you want is to use join, equals will work just fine in your case:


var validThresholds = new [] {new {ThresholdType = 3}, new {ThresholdType = 2}};
var manufacturerLevel = new [] {new {ThresholdType = 1}, new {ThresholdType = 2}};

(from r in validThresholds
join t in manufacturerLevel on r.ThresholdType equals t.ThresholdType
select t).ToList();

If you need to do equals by more than one field, use anonymous types:


var validThresholds = new [] {new {ThresholdType = 3, Foo = 3}, new {ThresholdType = 2,     Foo = 1}};
var manufacturerLevel = new [] {new {ThresholdType = 1, Foo = 1}, new {ThresholdType = 2, Foo = 1}};

(from r in validThresholds
join t in manufacturerLevel on new {r.Foo, r.ThresholdType} equals new {t.Foo, t.ThresholdType}
select t).Dump();



You can also do this, you can have your custom comparer to determine if an object is different from another, and then just use .Except on the collection of those objects.


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

And then get the difference like this:


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


I'm using this linq query (successfully in most instances) to check one List against another List. The objective is to return the objects which have a ThresholdType not already included in the validThresholds list.


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

For some reason, which is really confusing me, I am getting a result of 20 objects. From comparing a list of possible 9 objects against a list of 3 valid objects. Obviously I have made some error in the logic here, but I cannot see how I could get more results back than the sum of both collections! I am really interested to know why I am getting this result.


Originally I wanted to use a Join but that restricts me as it only allows the equals with no inequality operator.


Below I have created a sample application which recreates the issue.


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;
}
}
}

How can I correctly compare two lists and return the objects where a specific property value does not exist in the other?




How can I correctly compare two lists and return the objects where a specific property value does not exist in the other?



Something like this?


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


My intent is to add the objects from manufacturerLevel to validThresholds where any object in validThreshold doesn't have the same ThresholdType value as any object in manufacturerLevel



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

You may also want to consider whether what you're really trying to do is compile a Set of these objects. If you made validThresholds a HashSet<>, for example, with an IEqualityComparer<> based on the ThresholdType, you could simply Add all the items, and it would automatically ignore any whose ThresholdType was already represented in the collection.



You can do it like this:


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

EDIT:



My intent is to add the objects from manufacturerLevel to validThresholds where any object in validThreshold doesn't have the same ThresholdType value as any object in manufacturerLevel



If I understood it correctliy you need to merge the two collections, right?


var validThresholds= validThresholds.Union(manufacturerLevel);

Make sure you override properly the Equalsmethod in ConsumableThreshold



There is a big difference between join and two from operators. You query gives you all combinations of both lists minus those where threshold is not different. Your t will be repeated many times. What you want is to use join, equals will work just fine in your case:


var validThresholds = new [] {new {ThresholdType = 3}, new {ThresholdType = 2}};
var manufacturerLevel = new [] {new {ThresholdType = 1}, new {ThresholdType = 2}};

(from r in validThresholds
join t in manufacturerLevel on r.ThresholdType equals t.ThresholdType
select t).ToList();

If you need to do equals by more than one field, use anonymous types:


var validThresholds = new [] {new {ThresholdType = 3, Foo = 3}, new {ThresholdType = 2,     Foo = 1}};
var manufacturerLevel = new [] {new {ThresholdType = 1, Foo = 1}, new {ThresholdType = 2, Foo = 1}};

(from r in validThresholds
join t in manufacturerLevel on new {r.Foo, r.ThresholdType} equals new {t.Foo, t.ThresholdType}
select t).Dump();


You can also do this, you can have your custom comparer to determine if an object is different from another, and then just use .Except on the collection of those objects.


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

And then get the difference like this:


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

0 commentaires:

Enregistrer un commentaire