LINQ - Group To Model - c#

I have a list like below with more column. First two column is for entity A and second two column is for entity B. As you can see there is one to many relationship between these entities. So, I want to group this list to custom model.
QID ORDERNUMBER OPID POINT
1888 1 6902 4
1888 1 6903 3
1888 1 6904 2
1888 1 6905 1
1889 2 6906 4
1889 2 6907 3
1889 2 6908 2
1889 2 6909 1
1890 3 6910 4
1890 3 6911 3
1890 3 6912 2
1890 3 6913 1
First two column for Question object and other two column is for Options object list. This is my model
public class MyModel
{
public Question Question { get; set; }
public List<Option> Options { get; set; }
}
I need to group above table by QID. After that I need to take group key to Question object and assign QID's groups to list of Option object.
Simple demonstrade for one instance of MyModel should be;
MyModel > Question > QID:1888
ORDERNUMBER:1
> Options > [0] : OPID:6902
POINT:4
[1] : OPID:6903
POINT:3
[2] : OPID:6904
POINT:2
[3] : OPID:6905
POINT:1

Firstly, GroupBy QID, ORDERNUMBER, then, for each group, init the question and his questions
var models = list.GroupBy(q => new { q.QID, q.ORDERNUMBER})
.Select(g => new Model()
{
Question = new Question() { QID = g.Key.QID, ORDERNUMBER =g.Key.ORDERNUMBER} ,
Options = new List<Option>(g.ToList().Select(i => new Option() { OPID = i.OPID, POINT = i.POINT }))
})

Related

Find Common value against different id c# Linq

I have one table which is looking like this
ID
UserID
UserEncryptValue
1
1
abcd
2
2
1234
3
3
qwert
4
1
rstuv (Common value for user 1 and 2)
5
2
rstuv (Common value for user 1 and 2)
6
2
78901 (Common value for user 2 and 3)
7
3
78901 (Common value for user 2 and 3)
8
1
Hello123 (Common value for user 1,2 and 3)
9
2
Hello123 (Common value for user 1,2 and 3)
10
3
Hello123 (Common value for user 1,2 and 3)
Now I want to find if user 1 and 2 or 1, 2 and 3 have common value or not with use of Linq.
Assuming you're mapping that table to an actual object like 'UserData' like this:
public class UserData
{
public int Id { get; set; }
public int UserId { get; set; }
public string UserEncryptValue { get; set; }
}
You can get the common values like this (userData is a list of UserData and represents your data):
var searchId = 1;
var commonValues = userData.GroupBy(user => user.UserEncryptValue)
.Where(grp => grp.Count() > 1 && grp.Any(usr => usr.UserId == searchId))
.SelectMany(u => u);
This groups on the UserEncryptValue and only selects groups that have more than 1 value (has a match) and at least 1 of the user ids is equal to the searchId.
Table.Where(n => Table.Any(o => !(o === n) && o.UserEncryptValue == n.UserEncryptValue)).Select(n => n.UserID)
Will return a collection of user id's for members of collection Table where at least on other member of the table has the same value UserEncryptValue but is not the same object
Learn LINQ to understand how this works and what you can do to tweak it.
One way is to use GroupBy. In this case you would group by UserEncryptValue.
You can then examine each group and check which users are in each group.

LINQ QUERY TABLE

The number increases by 1 in the database as a staff member views something.
Example
abab : 1
cbcb : 1
dcdc: 1
abab : 1
abab : 1
I want to print who viewed how much in the table.
Example
abab : 3
cbcb : 1
dcdc : 1
but it doesn't work the way I want. The code I wrote is below
Count = _viewHistoryRepository.GetByExpression(f => f.MemberId == c.MemberId).Sum(s=> s.ViewsCount)
Output:
abab : 3
abab : 3
abab : 3
cbcb : 1
dcdc: 1
I want each name to appear once. Thank you
You need to use GroupBy then:
IEnumerable<string> query = _viewHistoryRepository
.GroupBy(x => x.MemberId)
.Select(g => $"{g.Key} : {g.Sum(x => x.ViewsCount)}");
So apparently you have a class similar to this:
class StaffMemberView
{
public string Name {get; set;}
public int ViewCount {get; set;} // in your input always 1
... // other properties
}
If your input indeed always have a value 1, it is enough to make groups of StaffMemberviews that have the same value for property Name. In parameter resultSelector count the number of elements in each group:
IEnumerable<StaffMemberView> staffMemberViews = ...
var result = staffMemberViews.GroupBy(
// keySelector: make groups with the same value for Name:
staffMemberView => staffMemberView.Name,
// parameter resultSelector, for every Name, and all StaffMemberViews that
// have this Name, make one new:
(name, staffMembersViewsWithThisName) => new
{
Name = name,
ViewCount = staffMemberViewsWithThisName.Count(),
});
If parameter ViewCount sometimes is not 1, then it is not enough to just Count the StaffMemberViews in each group, but you have to Sum the values of ViewCount.
Parameter resultSelector changes:
(name, staffMembersViewsWithThisName) => new
{
Name = name,
ViewCount = staffMemberViewsWithThisName
.Select(staffMemberView => staffMemberView.ViewCount)
.Sum(),
});

LINQ Query multiple orderby of joined tables

I have following LinQ query
var CGTABLE = (from cg in DbContext.CGTABLE
join tcg in DbContext.TCGTABLE on new { cg.CGroupId } equals new { tcg.CGroupId }
where tcg.TId == TId
select new {
CGroupId = cg.CGroupId,
CGroupCode = cg.CGroupCode,
Description = cg.Description,
C = cg.C,
DisplayOrder = cg.DisplayOrder
}).ToList();
CGTABLE = CGTABLE.OrderBy(g => g.DisplayOrder).ThenBy(g => g.C.OrderBy(c => c.CCode)).ToList();
which runs fine, but it is not doing second orderby using ThenBy ThenBy(g => g.C.OrderBy(c => c.CCode) What am I missing?
Sample data for better understanding.
Data in Tables
2
1
2
4
3
1
4
5
2
1
3
3
1
Should output after both outer and inner list ordered by
1
1
2
3
4
2
1
2
4
5
3
1
3
But Currently it is showing
1
4
5
2
1
2
1
2
4
3
3
3
1
You didn't want to order the main list, you are looking for a way to order inner list inside of outer one, I think.
So below code will do it for you:
var CGTABLE = (
from cg in DbContext.CGTABLE
join tcg in DbContext.TCGTABLE on new { cg.CGroupId } equals new { tcg.CGroupId }
where tcg.TId == TId
select new {
CGroupId = cg.CGroupId,
CGroupCode = cg.CGroupCode,
Description = cg.Description,
C = cg.C.OrderBy(x => x.CCode),
DisplayOrder = cg.DisplayOrder
}).ToList();
CGTABLE = CGTABLE.OrderBy(g => g.DisplayOrder).ToList();

Select Distinct rows using Linq

The data is as follow
ID Title Category About Link CategoryID
1 The Matrix Sci-Fi Text goes here http://... 1
2 The Simpsons Cartoon Text goes here http://... 2
3 Avengers Action Text goes here http://... 3
4 The Matrix Sci-Fi Text goes here http://... 1
5 The One Sci-Fi Text goes here http://... 1
6 The Hobbit Sci-Fi Text goes here http://... 1
I have a checkbox list containing the categories. The problem is if the user selects 'Action' and 'Sci-Fi' as category to display The Matrix will be displayed twice.
This is my try for getting unique rows in SQL Query.
select distinct title, about, link from mytable
inner join tableCategories on categoryID = tableCategoriesID
group by title, about, link
Using the LINQ,
(from table in movieTables
join x in categoryIDList
on categoryID equals x
slect table).Distinct()
Note that the categories are in a separate table linked by the categoryID.
Need help displaying unique or distinct rows in LINQ.
You can happily select your result into a list of whatever you want:
var v = from entry in tables
where matching_logic_here
select new {id = some_id, val=some_value};
and then you can run your distinct on that list (well, a ToList() on the above will make it one), based on your needs.
The following should illustrate what i mean (just paste into linqpad. if you're using VS, get rid of the .Dump():
void Main()
{
var input = new List<mock_entry> {
new mock_entry {id = 1, name="The Matrix", cat= "Sci-Fi"},
new mock_entry {id = 2, name="The Simpsons" ,cat= "Cartoon"},
new mock_entry {id = 3, name="Avengers" ,cat= "Action"},
new mock_entry {id = 4, name="The Matrix", cat= "Sci-Fi"},
new mock_entry {id = 5, name="The One" ,cat= "Sci-Fi"},
new mock_entry {id = 6, name="The Hobbit",cat= "Sci-Fi"},
};
var v = input.Where(e=>e.cat == "Action" || e.cat =="Sci-Fi")
.Dump()
.Select(e => new {n = e.name, c =e.cat})
.Dump()
;
var d = v.Distinct()
.Dump()
;
}
// Define other methods and classes here
public struct mock_entry {
public int id {get;set;}
public string name {get;set;}
public string cat {get;set;}
}
Another option would be to use DistinctBy from more linq as suggested in this question
Edit:
Even simpler, you can use GroupBy, and just select the first entry (you'll lose the id though, but up to you).
Here's an example that will work with the above:
var v = input.GroupBy (i => i.name)
.Select(e => e.First ())
.Dump()
.Where(e=>e.cat == "Action" || e.cat =="Sci-Fi")
.Dump()
;
will yield:
1 The Matrix Sci-Fi
3 Avengers Action
5 The One Sci-Fi
6 The Hobbit Sci-Fi

Filter a generic list based on another list

I have a generic list which needs to be filter based on another list (say, List<string>).
public class Model
{
public string ID { get; set;}
public string Make { get; set;}
}
List<Model> lstModel = new List<Model>();
And the lstModel is as follows
ID Make
---- -----------
5 MARUTI
4 BENZ
3 HYUNDAI
2 HONDA
1 TOYOTA
And i have another list which contains only car makers,ie
List<string> lstMakers = new List<string>() {"MARUTI", "HONDA"};
1) I need to filter lstModel which contains only items in lstMakers.
The output would be
ID Make
---- -----------
5 MARUTI
2 HONDA
2) Based on output (1), need another list of ids with 1 increment to each item in descending order,
The output would be List<int> ie,
6
5
3
2
Note: Using lambda expression / linq is more preferable
1 )
var list1 = lst.Where(x=>lstMakers.Contains(x.Make)).ToList();
2)
var list2 = list1.Select(x=>int.Parse(x.ID)+1)
.Concat(list1.Select(x=>int.Parse(x))
.OrderByDescending(x=>x)
.ToList();
Use Enumerable.Join and OrderByDescending:
var models = from maker in lstMakers
join model in lstModel
on maker equals model.Make
select model;
List<int> result = models
.Select(m => int.Parse(m.ID) + 1)
.OrderByDescending(i => i)
.ToList();
However, this selects two ints since only two models match. Your result contains 4 ints. I assume that your result is not related to your sample, is it?
but i need both the item and its incremental value,...
Now it's clear, use Enumerable.SelectMany with an array:
List<int> result = models
.Select(m => int.Parse(m.ID))
.SelectMany(id => new int[]{ id, id + 1 })
.OrderByDescending(id => id)
.Distinct()
.ToList();

Categories

Resources