I have (1,2,3) and i want insert in my table:
1-2
2-3
But I want exclude 2-1 and 3-2.
Any help?
First get the cartesian product of the items. Then exclude those with difference more than 1 and first number >= second number. Like this:
List<int> list = new List<int>(){1, 2, 3};
var result = from n1 in list
from n2 in list
select new {n1, n2};
result = result.Where(n=> (n.n1 < n.n2) && (n.n2 - n.n1 == 1)).ToList();
This will give you what you want:
Results
Related
I have a list of ordered products. I also have a list of index values. I want to pull out all products whose index is in the list of indexes. Right now I'm doing this:
var indexes = new List<int> { 1, 2, 5, 7, 10 };
var myProducts = orderedProducts.Where((pr, i) => indexes.Any(x => x == i)).ToList();
However, myProducts only has 2 elements in it: The products with indexes 1 and 2. It completely misses 5, 7, and 10. What is going on? How do I fix this?
Note: orderedProducts.Count is always greater than the maximum value of the indexes list.
orderedProducts is formed from the following:
orderedProducts = productDictionary[fam.Key]
.ToList()
.OrderBy(g => g.factor)
.ToList();
where g.factor is an int, fam.Key is an int key for the product dictionary. I've checked myProducts and it is indeed a List<Product> ordered by factor ascending.
prodDictionary is a Dictionary<int?, List<Product>>.
You missed something in your testing. You said "myProducts.Count is always greater than the maximum value of the indexes list". That makes no sense considering you said "myProducts only has 2 elements". orderedProducts.Count must be < 6. Thus the problem. You are pulling out elements by simply comparing the indexes in the List. You can "fix" the problem by adding more products to the list.
void Main()
{
var indexes = new List<int> { 1, 2, 5, 7, 10 };
var orderedProducts = new List<Product>();
orderedProducts.Add(new Product());
orderedProducts.Add(new Product());
orderedProducts.Add(new Product());
orderedProducts.Add(new Product());
orderedProducts.Add(new Product());
//orderedProducts.Add(new Product());//Add this in and you will see a result at index 5
//orderedProducts.Add(new Product());
//orderedProducts.Add(new Product());//7
//orderedProducts.Add(new Product());
//orderedProducts.Add(new Product());
//orderedProducts.Add(new Product());//10
var myProducts = orderedProducts.Where((pr, i) => indexes.Any(x => x == i)).ToList();
}
public class Product
{
}
Uncomment the products and you get 5 results as expected. Index of 10 on a 0 based array.
why not just indexes.Where(i => i < orderedProducts.Count).Select(i => orderedProducts[i]).ToList();?
Let's say I have this list:
1
1
1
1
2
2
2
3
I want to narrow it down with C# to a list with a maximum of two same items in a list so it would look like this:
1
1
2
2
3
I used to use 'distinct' like this:
string[] array = System.IO.File.ReadAllLines(#"C:\list.txt");
List<string> list = new List<string>(array);
List<string> distinct = list.Distinct().ToList();
but don't have an idea on how it could bring a max number of same values
You could do it with Linq as follows.
var Groups = Input.GroupBy( i => i );
var Result = Groups.SelectMany( iGroup => iGroup.Take(2) ).ToArray();
I have the below table AttachmentToTagMappings
And I have an array which contains some tag id as shown below and the size can change in every execution.
int[] tagIds= new int[] {1,2,9}; //again the number of elements can change in every execution for example in next execution it may be {1,2,7,12} because the this time the user is looking for the file(s) which are/is mapped to 1,2,7 and 12
Now I want to write a linq by which I can get fileId(s) which are mapped to the above array tagIds elements. i.e. in above table FileId 201 is mapped to 1,2 and 9 so retrieve it but not 202 cause its only mapped to 1 and 2.
Solution
To solve this problem, I would make use a couple of LINQs like GroupBy, let and Except.
Here is my solution:
var grp = context.AttachmentToTagMappings.GroupBy(x => x.TagId);
int[] tagIds = new int[] {1,2,9};
var fileIds = from g in grp
let grpFileIds = g.Select(y => y.FileId)
let remFileIds = tagIds.Except(grpFileIds)
where remFileIds.ToList().Count == 0
select g.Key;
Or,
int[] tagIds = new int[] {1,2,9};
var fileIds = from attm in context.AttachmentToTagMappings
group attm by new {attm.TagId} into g
let grpFileIds = g.Select(y => y.FileId)
let remFileIds = tagIds.Except(grpFileIds)
where remFileIds.ToList().Count == 0
select g.Key;
Assumption: attm.TagId type is the same as tagId, that is, an int
Input-Output Results
{1, 2} -> 201, 202
{1, 2, 9} -> 201
{1, 2, 7} -> 202
{1, 2, 7, 9} -> nothing
Explanation
Using GroupBy you could first group your AttachmentToTagMappings based on its TagId thus creating two groups, one identified by 201 and having three attm members whose tag ids are 1, 2, and 9 respectively. Another group has key of 202 with four attm members whose tag ids are 1, 2, 7, and 12 respectively.
Using let we want to create an IEnumerable<int> grpFileIds for each group. grpFileIds contains only the group's file ids
Next, Using Except we want to omit all the tagId in tagIds which is contained in grpFileIds, resulting in the remaining remFileIds
If the remFileIds.Count is zero, it means all items in tagIds has a pair in the grpFields. Otherwise, if the remFileIds.Count is greater than zero, meaning at least there is one tagId which the group does not have
Select all keys in the group (that is 201, 202, etc) whose remFileIds.Count is zero.
Contains should be translated to an IN clause in SQL which seems to be what you want:
where tagIds.Contains(attm.TagId)
try .Contain() :
var attachments = from attm in context.AttachmentToTagMappings
where tagIds.Contains(attm.TagId)
select new { attm.FileId};
Or you can use || instead of && but i think .Contains() better less code;)
As I understand your question, you need to get a list of attachments which its tagId exists in an array.
var attachments = from attm in context.AttachmentToTagMappings
where
tagIds.Any(id=>id==attm.TagId)
select new { attm.FileId};
I think this is what you are looking for:
var ids = {1, 2, 3};
var files = context.Files.Where(file => ids.Contains(file.TagId));
if(!ids.AsEnumerable().Except(files.Select(f => f.TagId).AsEnumerable()).Any()){
return files;
}
return null;
Select all files and check that there aren't any ids that don't match to an id in the files and return list of files. If not then return null.
Syntax may not be exact as not tested.
I know that I can use .Min() to get minimum value from column, but how to get minimum value in a row?
I have following LINQ query (for testing purposes):
from p in Pravidloes
where p.DulezitostId == 3
where p.ZpozdeniId == 1 || p.ZpozdeniId == 2
where p.SpolehlivostId == 2 || p.SpolehlivostId == 3
group p by p.VysledekId into g
select new {
result = g.Key,
value = g
}
Which results into this:
I would however like to get only the MIN value of following three columns:
DulezitostId, ZpozdeniId, SpolehlivostId as a value in:
select new {
result = g.Key,
value = g // <-- here
}
The final result then should look like:
result: 2, value: 1
result: 3, value: 2
I have been looking for similar questions here and googled for few examples with grouping and aggregating queries, but found nothing that would move me forward with this problem.
Btw: Solution isn't limited to linq, if you know better way how to do it.
You could create an array of the values and do Min on those.
select new {
result = g.Key,
value = g.SelectMany(x => new int[] { x.DulezitostId, x.ZpozdeniId, x.SpolehlivostId }).Min()
}
This will return the min for those 3 values in each grouping for ALL rows of that grouping.
Which would result in something like this...
result: 3, value: 1
The below will select the min for each row in the grouping...
select new {
result = g.Key,
value = g.Select(x => new int[] { x.DulezitostId, x.ZpozdeniId, x.SpolehlivostId }.Min())
}
Which would result in something like this...
result: 3, value: 1, 2
The best solution if you're using straight LINQ is Chad's answer. However, if you're using Linq To SQL it won't work because you can't construct an array like that.
Unfortunately, I believe the only way to do this in Linq To Sql is to use Math.Min repeatedly:
select new {
result = g.Key,
value = Math.Min(Math.Min(DulezitostId, ZpozdeniId), SpolehlivostId)
}
This will generate some ugly CASE WHEN ... statements, but it works.
The main advantage of doing it this way is that you're only returning the data you need from SQL (instead of returning all 3 columns and doing the Min in the application).
I have the following query:
var results = from theData in GeometricAverage
group theData by new { study = theData.study, groupNumber = theData.groupNumber, GeoAverage= theData.GeoAverage } into grp
select new
{
study = grp.Key.study,
groupNumber = grp.Key.groupNumber,
TGI = testFunction(grp.Key.GeoAverage, Also here I want to pass in the GeoAverage for only group 1 (but for each individual study))
};
What I want to do is that for each study, there are multiple groups with a GeoAverage figure for each group. The TGI is calculated by passing the GeoAverage figure for each group and the GeoAverage figure for group 1 (on each study) into the testFunction. I can't figure out how to pass in the value just for group 1.
Hope this makes sense.
EDIT: Sample of data:
Study Group GeoAverage
1 1 3
1 2 5
1 3 6
2 1 2
2 2 3
2 3 9
So, for the above data, I would want each GeoAverage figure for each group, to be evaluated against the GeoAverage figure of group 1 within that same study. So if I have say a function:
int foo(int a, int b)
{
return a * b;
}
Using the data above, I would first evaluate study 1, group 1 against itself, so pass in GeoAverage 3 twice and return 9. For Study 1, group 2, pass in group 2 GA at 5, and that studys group1 GA at 3, returning 15.
Have now worked it out. I iterate through a collection of data that I want the value to be stored against and use the following two LINQ queries:
foreach (var data in compoundData)
{
var controlValue = from d in GeometricAverage
where d.study == data.study
where d.groupNumber == "1"
select d.GeoAverage;
var treatmentValue = from l in GeometricAverage
where l.study == data.study
where l.groupNumber == data.groupNumber
select l.GeoAverage;
data.TGI = CalculateTGI(controlValue, treatmentValue);
}