Multiple Unique Requirements
-
Is there a way to do this with out looping? Example: MyDataSet has 3 paramaters ParamA, ParamB, and ofcourse ParamC Currently I have to do this...
var aUnique = data.Select(a => a.ParamA).Distinct(); int count = 0; foreach (var paramA in aUnique ) { //Get unique b var bUnique = data.Select(b => b.ParamB).Distinct(); foreach (var paramB in bUnique) { //Query with our current constraints var results = from items in data where items.ParamA == paramA where items.ParamB == paramB select items; int cCount = data.Select(c => c.ParamC).Distinct().Count(); count += cCount ; } }
I would like the same logic in a single LINQ statement if it can be done. The loop seems quite slow...
ASCII stupid question, get a stupid ANSI
-
Is there a way to do this with out looping? Example: MyDataSet has 3 paramaters ParamA, ParamB, and ofcourse ParamC Currently I have to do this...
var aUnique = data.Select(a => a.ParamA).Distinct(); int count = 0; foreach (var paramA in aUnique ) { //Get unique b var bUnique = data.Select(b => b.ParamB).Distinct(); foreach (var paramB in bUnique) { //Query with our current constraints var results = from items in data where items.ParamA == paramA where items.ParamB == paramB select items; int cCount = data.Select(c => c.ParamC).Distinct().Count(); count += cCount ; } }
I would like the same logic in a single LINQ statement if it can be done. The loop seems quite slow...
ASCII stupid question, get a stupid ANSI
-
Is there a way to do this with out looping? Example: MyDataSet has 3 paramaters ParamA, ParamB, and ofcourse ParamC Currently I have to do this...
var aUnique = data.Select(a => a.ParamA).Distinct(); int count = 0; foreach (var paramA in aUnique ) { //Get unique b var bUnique = data.Select(b => b.ParamB).Distinct(); foreach (var paramB in bUnique) { //Query with our current constraints var results = from items in data where items.ParamA == paramA where items.ParamB == paramB select items; int cCount = data.Select(c => c.ParamC).Distinct().Count(); count += cCount ; } }
I would like the same logic in a single LINQ statement if it can be done. The loop seems quite slow...
ASCII stupid question, get a stupid ANSI
It looks like you are trying to group the items to me. If you are trying to find how many items there are for each combination of (A, B, C), a Group By should work.
-
It looks like you are trying to group the items to me. If you are trying to find how many items there are for each combination of (A, B, C), a Group By should work.
-
Is this the same?
var distinct = (from item in data
select new { item.ParamA, item.ParamB, item.ParamC}).Distinct();int count = distinct.Count();
ASCII stupid question, get a stupid ANSI
no it is not the same.
Collin Jasnoch wrote:
ar distinct = (from item in data select new { item.ParamA, item.ParamB, item.ParamC}).Distinct();
this will give you distinct groups of ParamA,B and C. but ParamA will not be unique. Ex: 1,2,3 and 1,3,2. As you can see A is not unique but the hole collection of Params is unique. [EDIT] Better said it won't work. I mean it will compile and execute but it won't give you distinct combinations of the 3 params because it doesn't know how to compare them. You need to supply the Distinct(IComparer); In fact here is one possible solution to your problem:
//1) create a class
public class ThreeParams{
public int ParamA{get;set;}
public int ParamB{get;set;}
public int ParamC{get;set;}public override string ToString() { return ParamA + "\\t" + ParamB + "\\t" + ParamC; }
//you could Implement IEqutable in here or to provide more flexibility out of the class as
//i did in listing/point 2)
}//2) Create a IEqualityComparer for your class
public class ParamsEqualityComparer : IEqualityComparer<ThreeParams>
{
//of course you can chage the implementation to suit your needs
public bool Equals(ThreeParams a, ThreeParams b)
{
return a.ParamA.Equals(b.ParamA)
|| a.ParamB.Equals(b.ParamB)
|| a.ParamC.Equals(b.ParamC);
}public int GetHashCode(ThreeParams a) { return a.ToString().GetHashCode(); } }
//3) now all you have to do is:
var distinct = (from item in data
select item).Distinct( new ParamsEqualityComparer());
//data is a list of ThreeSomethingmodified on Saturday, February 20, 2010 4:04 AM
-
no it is not the same.
Collin Jasnoch wrote:
ar distinct = (from item in data select new { item.ParamA, item.ParamB, item.ParamC}).Distinct();
this will give you distinct groups of ParamA,B and C. but ParamA will not be unique. Ex: 1,2,3 and 1,3,2. As you can see A is not unique but the hole collection of Params is unique. [EDIT] Better said it won't work. I mean it will compile and execute but it won't give you distinct combinations of the 3 params because it doesn't know how to compare them. You need to supply the Distinct(IComparer); In fact here is one possible solution to your problem:
//1) create a class
public class ThreeParams{
public int ParamA{get;set;}
public int ParamB{get;set;}
public int ParamC{get;set;}public override string ToString() { return ParamA + "\\t" + ParamB + "\\t" + ParamC; }
//you could Implement IEqutable in here or to provide more flexibility out of the class as
//i did in listing/point 2)
}//2) Create a IEqualityComparer for your class
public class ParamsEqualityComparer : IEqualityComparer<ThreeParams>
{
//of course you can chage the implementation to suit your needs
public bool Equals(ThreeParams a, ThreeParams b)
{
return a.ParamA.Equals(b.ParamA)
|| a.ParamB.Equals(b.ParamB)
|| a.ParamC.Equals(b.ParamC);
}public int GetHashCode(ThreeParams a) { return a.ToString().GetHashCode(); } }
//3) now all you have to do is:
var distinct = (from item in data
select item).Distinct( new ParamsEqualityComparer());
//data is a list of ThreeSomethingmodified on Saturday, February 20, 2010 4:04 AM
OK that helps. I actually already have my object inherit from IQuatable so if I use a separate Comparer it seems I can get it to work the way I want. I am a bit confused by what you said though
MDL=>Moshu wrote:
this will give you distinct groups of ParamA,B and C. but ParamA will not be unique. Ex: 1,2,3 and 1,3,2. As you can see A is not unique but the hole collection of Params is unique.
Maybe I was not originally doing what I want, but this sounds like what I am wanting. To explain a little more detail. The params are identifiers for product. ParamA is serialized (meaning there exists only one occurance of it for some product). So as an example lets say ParamA is "XXXX23" in one case and "XXXX24" in another. ParamB and ParamC are not serialized. Meaning that both "XXXX23" and "XXXX24" could have the same values for ParamB and/or ParamC but the actual product is different then. FOr example here are some entries. 1. ParamA = "XXXX24" ParamB = 1 ParamC = 32 2. ParamA = "XXXX24" ParamB = 2 ParamC = 32 3. ParamA = "XXXX23" ParamB = 2 ParamC = 32 4. ParamA = "XXXX23" ParamB = 2 ParamC = 32 5. ParamA = "XXXX24" ParamB = 1 ParamC = 31 What I want returned is items 1,2,(3/4), and 5. Note the only same product is 3 and 4 so one istance of their entry is returned. So is this what my current code is doing?
ASCII stupid question, get a stupid ANSI
-
OK that helps. I actually already have my object inherit from IQuatable so if I use a separate Comparer it seems I can get it to work the way I want. I am a bit confused by what you said though
MDL=>Moshu wrote:
this will give you distinct groups of ParamA,B and C. but ParamA will not be unique. Ex: 1,2,3 and 1,3,2. As you can see A is not unique but the hole collection of Params is unique.
Maybe I was not originally doing what I want, but this sounds like what I am wanting. To explain a little more detail. The params are identifiers for product. ParamA is serialized (meaning there exists only one occurance of it for some product). So as an example lets say ParamA is "XXXX23" in one case and "XXXX24" in another. ParamB and ParamC are not serialized. Meaning that both "XXXX23" and "XXXX24" could have the same values for ParamB and/or ParamC but the actual product is different then. FOr example here are some entries. 1. ParamA = "XXXX24" ParamB = 1 ParamC = 32 2. ParamA = "XXXX24" ParamB = 2 ParamC = 32 3. ParamA = "XXXX23" ParamB = 2 ParamC = 32 4. ParamA = "XXXX23" ParamB = 2 ParamC = 32 5. ParamA = "XXXX24" ParamB = 1 ParamC = 31 What I want returned is items 1,2,(3/4), and 5. Note the only same product is 3 and 4 so one istance of their entry is returned. So is this what my current code is doing?
ASCII stupid question, get a stupid ANSI
Yeah I misunderstood what you wanted. Now, I don't know how you implemented the IEqualityComparer. So i don't know what it does. But what I showed in my previous post it doesn't do that. [Edit]It gives you only distinct combination where A is distinct so 1,2,4 but not 1,4,2.[/Edit] If I understood well you need to return distinct products and a product is distinct as long as ParamA is distinct or the combination of B and C is distinct if the ParamA is the same. This should do it:
public bool Equals(ThreeParams a, ThreeParams b){
if(a.ParamA == b.ParamA){
if((a.ParamB == b.ParamB) && (a.ParamC == b.ParamC)){
return true;
}
else{
return false;
}
}
return false;
}modified on Monday, February 22, 2010 12:17 PM
-
Yeah I misunderstood what you wanted. Now, I don't know how you implemented the IEqualityComparer. So i don't know what it does. But what I showed in my previous post it doesn't do that. [Edit]It gives you only distinct combination where A is distinct so 1,2,4 but not 1,4,2.[/Edit] If I understood well you need to return distinct products and a product is distinct as long as ParamA is distinct or the combination of B and C is distinct if the ParamA is the same. This should do it:
public bool Equals(ThreeParams a, ThreeParams b){
if(a.ParamA == b.ParamA){
if((a.ParamB == b.ParamB) && (a.ParamC == b.ParamC)){
return true;
}
else{
return false;
}
}
return false;
}modified on Monday, February 22, 2010 12:17 PM
I still do not understand why the LINQ query I wrote doesn't do that.. Here is some test code... Simple form with a dataset getting initialized. Note that 7 is posted. Because there are 3 entires with "X1", 1, 1 and 2 entries with "X2", 2, 1 and numerous combinations inbetween. Total entries is 10. so (1,2), 3, 4, 5, 6,(7,8,9), 10 for a total of 7. So I seem to be getting what I would expect... Am I missing a case where I get an extra count or do not receive a count?
public partial class Form1 : Form { List<MyDataSet> dataSet; public Form1() { InitializeComponent(); } private void bttnGo\_Click(object sender, EventArgs e) { FillDataSet(); var distinct = (from items in dataSet select new { SerializedParam = items.SerializedParam, NonSerializedParam2 = items.NonSerializedParam2, NonSerializedParam1 = items.NonSerializedParam1 }).Distinct(); MessageBox.Show(distinct.Count().ToString()); } private void FillDataSet() { dataSet = new List<MyDataSet>(); dataSet.Add(new MyDataSet() { SerializedParam = "X1", NonSerializedParam1 = 1, NonSerializedParam2 = 1 }); dataSet.Add(new MyDataSet() { SerializedParam = "X1", NonSerializedParam1 = 1, NonSerializedParam2 = 1 }); dataSet.Add(new MyDataSet() { SerializedParam = "X1", NonSerializedParam1 = 1, NonSerializedParam2 = 2 }); dataSet.Add(new MyDataSet() { SerializedParam = "X1", NonSerializedParam1 = 2, NonSerializedParam2 = 1 }); dataSet.Add(new MyDataSet() { SerializedParam = "X2", NonSerializedParam1 = 1, NonSerializedParam2 = 1 }); dataSet.Add(new MyDataSet() { SerializedParam = "X2", NonSerializedParam1 = 1, NonSerializedParam2 = 2 }); dataSet.Add(new MyDataSet() { SerializedParam = "X2", NonSerializedParam1 = 2, NonSerializedParam2 =
-
I still do not understand why the LINQ query I wrote doesn't do that.. Here is some test code... Simple form with a dataset getting initialized. Note that 7 is posted. Because there are 3 entires with "X1", 1, 1 and 2 entries with "X2", 2, 1 and numerous combinations inbetween. Total entries is 10. so (1,2), 3, 4, 5, 6,(7,8,9), 10 for a total of 7. So I seem to be getting what I would expect... Am I missing a case where I get an extra count or do not receive a count?
public partial class Form1 : Form { List<MyDataSet> dataSet; public Form1() { InitializeComponent(); } private void bttnGo\_Click(object sender, EventArgs e) { FillDataSet(); var distinct = (from items in dataSet select new { SerializedParam = items.SerializedParam, NonSerializedParam2 = items.NonSerializedParam2, NonSerializedParam1 = items.NonSerializedParam1 }).Distinct(); MessageBox.Show(distinct.Count().ToString()); } private void FillDataSet() { dataSet = new List<MyDataSet>(); dataSet.Add(new MyDataSet() { SerializedParam = "X1", NonSerializedParam1 = 1, NonSerializedParam2 = 1 }); dataSet.Add(new MyDataSet() { SerializedParam = "X1", NonSerializedParam1 = 1, NonSerializedParam2 = 1 }); dataSet.Add(new MyDataSet() { SerializedParam = "X1", NonSerializedParam1 = 1, NonSerializedParam2 = 2 }); dataSet.Add(new MyDataSet() { SerializedParam = "X1", NonSerializedParam1 = 2, NonSerializedParam2 = 1 }); dataSet.Add(new MyDataSet() { SerializedParam = "X2", NonSerializedParam1 = 1, NonSerializedParam2 = 1 }); dataSet.Add(new MyDataSet() { SerializedParam = "X2", NonSerializedParam1 = 1, NonSerializedParam2 = 2 }); dataSet.Add(new MyDataSet() { SerializedParam = "X2", NonSerializedParam1 = 2, NonSerializedParam2 =
Collin Jasnoch wrote:
I still do not understand why the LINQ query I wrote doesn't do that.. Here is some test code...
But 7 is supposed to return so what is the problem? What LINQ query doesn't work? You mean your initial query? For your needs it just happens that it works. The compiler creates a default implementation for an anonymous type that enforce the combination of property(s), field(s) to be unique. OK. You're not selecting MyDataSet objects but you're selecting somethig like this:
internal class ???
{
public string PanleID{get;set;}
public int PartOnStrip {get;set;}
.....
}
//when you do something like select new{Bla ="Blah"}
//the compiler will automatically create an anonymous type/class for you.
//it knows you want to select a string in this case named Bla so it will create
//a class like this aprox.
internal class ???
{
public string Bla{get;set;}
}
//This is the magic behind the var keyword in a LINQ query.That's why it works for your special need. I thought that you wanted distinct values for paramA but you don't. So ignore my first reply. Now: 1)If you modify your click event to something like this
private void bttnGo_Click(object sender, EventArgs e)
{
FillDataSet();
var distinct =
(from items in dataSet
select new MyDataSet//see the new MyDataSet added.
//Now it selects MyDataSet objects until now it selected
// an anonymous type.
{
SerializedParam = items.SerializedParam,
NonSerializedParam1 = items.NonSerializedParam2,
NonSerializedParam2 = items.NonSerializedParam1
}).Distinct();
MessageBox.Show(distinct.Count().ToString());//you'll get 10 all of them
//because it does not know how to compare them. On the internal
//annonymous type it enforeced the rule mentioned above.
} -
Collin Jasnoch wrote:
I still do not understand why the LINQ query I wrote doesn't do that.. Here is some test code...
But 7 is supposed to return so what is the problem? What LINQ query doesn't work? You mean your initial query? For your needs it just happens that it works. The compiler creates a default implementation for an anonymous type that enforce the combination of property(s), field(s) to be unique. OK. You're not selecting MyDataSet objects but you're selecting somethig like this:
internal class ???
{
public string PanleID{get;set;}
public int PartOnStrip {get;set;}
.....
}
//when you do something like select new{Bla ="Blah"}
//the compiler will automatically create an anonymous type/class for you.
//it knows you want to select a string in this case named Bla so it will create
//a class like this aprox.
internal class ???
{
public string Bla{get;set;}
}
//This is the magic behind the var keyword in a LINQ query.That's why it works for your special need. I thought that you wanted distinct values for paramA but you don't. So ignore my first reply. Now: 1)If you modify your click event to something like this
private void bttnGo_Click(object sender, EventArgs e)
{
FillDataSet();
var distinct =
(from items in dataSet
select new MyDataSet//see the new MyDataSet added.
//Now it selects MyDataSet objects until now it selected
// an anonymous type.
{
SerializedParam = items.SerializedParam,
NonSerializedParam1 = items.NonSerializedParam2,
NonSerializedParam2 = items.NonSerializedParam1
}).Distinct();
MessageBox.Show(distinct.Count().ToString());//you'll get 10 all of them
//because it does not know how to compare them. On the internal
//annonymous type it enforeced the rule mentioned above.
}