I'm trying to create nested group with dynamic query.
Following are my collection of data
var invoices = new List < Purchase > () {
new Purchase() {
Id = 1, Customer = "a", Date = DateTime.Parse("1/1/2009")
}, new Purchase() {
Id = 2, Customer = "a", Date = DateTime.Parse("1/2/2009")
}, new Purchase() {
Id = 3, Customer = "a", Date = DateTime.Parse("1/2/2009")
}, new Purchase() {
Id = 4, Customer = "b", Date = DateTime.Parse("1/1/2009")
}, new Purchase() {
Id = 5, Customer = "b", Date = DateTime.Parse("1/1/2009")
}, new Purchase() {
Id = 6, Customer = "b", Date = DateTime.Parse("1/2/2009")
}
};
This linq query is returning the desired result.
var tree = invoices.GroupBy(x => x.Date).Select(x => new
{
Key = x.Key,
Items = x.GroupBy(y => y.Customer).Select(y => new
{
Key = y.Key,
Items = y
})
}).ToList();
Below is the output of the above linq query
But I just need to group different columns in different order.
So that I try to create dynamic linq query. But my code block result not same as my previous linq query.
var groupedInvoiceItems = invoices.AsQueryable().GroupBy("new (Date, Customer)", "it");
You could do this with Generics. Just Pass in your Lambda to a generic method.
Something like:
private IEnumerable<PurchaseGrp> BuildList<TSource>(IQueryable<TSource> allRecords,
Func<TSource, string> selector)
{
var result = allRecords.GroupBy(x = > x.selector(x));
return result;
}
The return type could be a new Grouped type PurchaseGrp or the same as your source (Purchase).
Related
I have a list lstCollectionInstances which has 4 collection instance,
var lstCollectionInstances = new List<CollectionInstance>
{
new CollectionInstance
{
Name = "A",
CollectionProperties = new List<CollectionProperty>
{
new CollectionProperty {Name = "P1", Value = 10, DataType = "D"}
}
},
new CollectionInstance
{
Name = "A",
CollectionProperties = new List<CollectionProperty>
{
new CollectionProperty {Name = "P2", Value = "H1", DataType = "S"}
}
},
new CollectionInstance
{
Name = "B",
CollectionProperties = new List<CollectionProperty>
{
new CollectionProperty {Name = "P1", Value = 20, DataType = "D"}
}
},
new CollectionInstance
{
Name = "B",
CollectionProperties = new List<CollectionProperty>
{
new CollectionProperty {Name = "P2", Value = "H2", DataType = "S"}
}
},
};
Now when I filter it based on CollectionProperty data types D it's should give me 2 records, but below code giving me all 4 records, what is missing here?
var X = lstCollectionInstances.Select(x => new CollectionInstance
{
Name = x.Name,
CollectionProperties = x.CollectionProperties.Where(cp => cp.DataType == "D").ToList()
}).ToList();
This one selects all instances with a property of type D.
var result= lstCollectionInstances
.Where(x => x.CollectionProperties.Any(y => y.DataType == "D"))
.ToList();
It is because you're executing Select in each item of lstCollectionInstances and Where in CollectionProperties. It will return 4 items which 2 of them have empty CollectionProperties. You should execute Where first like:
var X = lstCollectionInstances.Where(a => a.CollectionProperties.Any(cp => cp.DataType == "D")).Select(x => new CollectionInstance
{
Name = x.Name,
CollectionProperties = x.CollectionProperties
}).ToList();
I'm writing a tag search in C# MVC, but I'm only able to get all the results that have one of the words. - The output should be only where all the input words matches, and exclude if e.g. 2 words are in the input, but only one of them matches.
My code so far:
List<String> list = Request["tags"].Split(' ').ToList();
KDBEntities q = new KDBEntities();
var query = (from tag in q.KDB_tags join question in q.KDB_questions on tag.question_id equals question.id where list.Any(x => x.Equals(tag.tag)) select question);
var Rquery = query.GroupBy(x => x.id).Select(grp => grp.FirstOrDefault()).ToList();
return View(Rquery);
I've been trying to figure this out for quite a while, but with no luck.
Hope this makes sense, and any of you can help me.
Tags list:
List<TagObj> tags = new List<TagObj>()
{
new TagObj() { Id = 1, QuestionId = 1, Tag = "news" },
new TagObj() { Id = 2, QuestionId = 1, Tag = "sports" },
new TagObj() { Id = 3, QuestionId = 1, Tag = "famous" },
new TagObj() { Id = 4, QuestionId = 2, Tag = "news" },
new TagObj() { Id = 5, QuestionId = 2, Tag = "sports" },
new TagObj() { Id = 6, QuestionId = 3, Tag = "news" },
new TagObj() { Id = 7, QuestionId = 4, Tag = "funny" },
};
Questions list:
List<QuestionObj> questions = new List<QuestionObj>()
{
new QuestionObj(){ QuestionId = 1, Question = "Whats up footballers?" },
new QuestionObj(){ QuestionId = 2, Question = "These are famous news?" },
new QuestionObj(){ QuestionId = 3, Question = "Read all about it?" },
new QuestionObj(){ QuestionId = 4, Question = "You know whats funny?" }
};
These are incoming tags from the request:
var incomingTags = new List<string>() { "news", "sports" };
These are the queries:
var query = from t in tags
join q in questions on t.QuestionId equals q.QuestionId
where incomingTags.Contains(t.Tag)
select new { question = q, tag = t };
var result = query.
GroupBy(g => g.question.QuestionId).
Where(g => g.ToList().Select(l => l.tag.Tag).SequenceEqual(incomingTags)).
Select(s => s.First().question).ToList();
How can I transform this dictionary to list
var dict = new Dictionary<string, List<string>>();
dict.Add("1", new List<string>() { "a", "b" });
dict.Add("2", new List<string>() { "a", "c" });
I'm expecting this output
List<dynamic> = new List<dynamic>()
{
new { id = "1", value = "a" }
new { id = "1", value = "a" }
new { id = "2", value = "a" }
new { id = "2", value = "a" }
}
I've tried this but can't get the values of the nested collections:
dict.Select(c => new { id=c.Key, value= c.Value })
Use SelectMany to return multiple items for each KeyValuePair. Then for each pair use Select on the Value:
var result = dict.SelectMany(pair => pair.Value.Select(item =>
new { id = pair.Key, value = item }));
Result:
I have a list of ids:
var IdList = new int[]{1, 2};
I also have a list of users:
var userList = new List<User>()
{
new User() {Id = 1, Name = "User1" },
new User() {Id = 1, Name = "User2" },
new User() {Id = 2, Name = "User2" },
new User() {Id = 1, Name = "User3" },
new User() {Id = 1, Name = "User4" },
new User() {Id = 2, Name = "User4" }
};
I want to get a list of users that must contain all the Ids from the IdList. So in this example I want to return User2 and User4. I've seen other subset examples that are just using Except and return boolean and even when adapting to my needs do not produce the correct results. I also saw one marked as duplicate (Similar Question) which is trying to do exactly this but did not agree that it was a duplicate and was never truly answered. I have attempted:
userList.Where(u => IdList.All(i => i == u.Id)).ToList();
that will not return anything.
Your question is a little confusing. You say you want to get a list of users that must contain all the Ids from the IdList and your expected output is User 2 and 4. That does not makes sense because your IdList has 1 and 2.
Also you have more than one record with Id 1. User1, User2 and User3 has same Id. What is the pattern to get one record from this ?
Assuming you do not have duplicate data and you want subset of items based on the items int eh idList, You can use LINQ Contains method.
var IdList = new int[]{1, 2};
var userList = new List<User>()
{
new User() {Id = 1, Name = "User1" },
new User() {Id = 2, Name = "User2" },
new User() {Id = 3, Name = "User3" },
new User() {Id = 4, Name = "User4" }
};
var subSet = userList.Where(d=>IdList.Contains(d.Id);
//subSet will have records for User1 and User2
Use Bellow 1Line linq code.
var q = userList.GroupBy(c => c.Name).Where(c => IdList.All(ccc => userList.Where(cc => cc.Name == c.Key).Any(cc => cc.Id == ccc))).ToList();
and this code return User2 and User4
Well, this is not elegant, but works:
List<string> result = new List<string>();
result = userList.Where(x => x.Id == IdList[0]).
Select(x => x.Name).ToList();
for(int i =1; i<IdList.Count();i++)
{
result = userList.Where(x => x.Id == IdList[i]).
Select(x => x.Name).ToList().
Intersect(result).ToList();
}
I have 2 arrays of different types one is from file and one is from a SQL Database - LINQ to SQL. I'm trying to delete non matching items from my database against items I receive via the file. (I mention this in case there is a more efficient way to do what I'm trying to achieve).
I've drafted up a couple of anonymous arrays to show what I am trying to do:
var a = new[] {
new { code = "A", subid = 1, test = "dunno" }, new { code = "A", subid = 2, test = "dunno" }, new { code = "A", subid = 3, test = "dunno" },
new { code = "B", subid = 1, test = "dunno" }, new { code = "B", subid = 2, test = "dunno" }, new { code = "B", subid = 3, test = "dunno" }
};
var c = new[] {
new { code = "A", subid = 1 }, new { code = "A", subid = 2 },
new { code = "B", subid = 1 }, new { code = "B", subid = 2 }
};
I need it to return the items that do not match e.g. new { code = "A", subid = 3 } and new { code = "B", subid = 3 }
var b = (from items in a
where c.Any(d => d.code == items.code && d.subid != items.subid)
select items);
and
var b = (from items in a
where c.Where(d=> d.code == items.code).Any(d => d.subid != items.subid)
select items);
I've tried these but they just seem to return all the items. How do I do this?
Use Enumerable.Except
var nonMatchingItems = a.Except(c);
Full sample:
var a = new[] {
new { code = "A", subid = 1 },
new { code = "A", subid = 2 },
new { code = "A", subid = 3 },
new { code = "B", subid = 1 },
new { code = "B", subid = 2 },
new { code = "B", subid = 3 }
};
var c = new[] {
new { code = "A", subid = 1 },
new { code = "A", subid = 2 },
new { code = "B", subid = 1 },
new { code = "B", subid = 2 }
};
foreach(vat item in a.Except(c))
Console.WriteLine(item);
// { code = A, subid = 3 }
// { code = B, subid = 3 }
UPDATE (if you have different types, and want to find matches of some set of fields, then use join of sequences, and remove all items from a which matched some items in c:
var matchingItems = from aa in a
join cc in c
on new { aa.code, aa.subid } equals // properties subset
new { cc.code, cc.subid } // same subset
select aa; // select inner item from join
var nonMatchingItems = a.Except(matchingItems);