Reputation: 443
I have two Generic lists having objects of class :
class Subject
{
public string Code { get; set; }
public string Name { get; set; }
}
And another class as below :
class Student
{
public string RollNo { get; set; }
public string Name { get; set;
}
And a List of type having Roll No and Subject codes as KeyValuePair for student as below :
List<KeyValuePair<string,string>> RoleList=
new List<KeyValuePair<string,string>> ();
Student st1=new Student();
Subject sb1=new Subject();
Subject sb2=new Subject();
Subject sb3=new Subject();
RoleList.Add(new KeyValuePair<string,string>(st1.RollNo,sb1.Code));
RoleList.Add(new KeyValuePair<string,string>(st1.RollNo,sb2.Code));
RoleList.Add(new KeyValuePair<string,string>(st1.RollNo,sb3.Code));
What I need is another Dictionary of type
Dictionary<string, List<Subject>> StSbList =
new Dictionary<string, List<Subject>>();
where StSbList should have a list of subjects for given student using dictionary RoleList having all the subjects for a given Roll No. using LINQ in C# 4.0 , something like
StSbList(st1.RollNo, {sb1,sb2,sb3});
I tried and was able merge to similar collections but struck with different type of collections. Any suggestions on any other better approach.
As rightly pointed by Douglas and Martin, both the solutions are working fine but on my test data ToLookup works faster so used the same.
Solution 1
Dictionary<string, List<Subject>> stSbList =
RoleList.GroupBy(kvp => kvp.Key)
.ToDictionary(
grouping => grouping.Key,
grouping => grouping.Select(kvp => (from sub in listSub
where sub.Code.Equals(kvp.Value)
select sub).First()).ToList(),
EqualityComparer<string>.Default);
Solution 2
var tSbList = RoleList.ToLookup(kvp => kvp.Key, kvp =>
(from sub in listSub
where sub.Code.Equals(kvp.Value)
select sub).First());
Upvotes: 1
Views: 3771
Reputation: 106836
To get you desired dicionary you can use the ToLookup
extension method.
You want to keep the Subject
objects but in your question you seem to throw them away and only store their code in the dictionary. I have taken the liberty to slightly modify how you create RoleList
:
var subject1 = new Subject { "Code 1", "Subject 1" };
var subject2 = new Subject { "Code 2", "Subject 2" };
var subject3 = new Subject { "Code 3", "Subject 3" };
var RoleList = new List<KeyValuePair<string, Subject>() {
"Roll 1", subject1,
"Roll 1", subject2,
"Roll 1", subject3,
"Roll 2", subject2,
"Roll 2", subject3
}
StSbList = RoleList.ToLookup(kvp => kvp.Key, kvp => kvp.Value);
Assuming that RoleList
has the following data:
Key | Value -------+--------- Roll 1 | subject1 Roll 1 | subject2 Roll 1 | subject3 Roll 2 | subject2 Roll 2 | subject3
The StSbList
will contain the following data:
Key | Value -------+----------------------------- Roll 1 | subject1, subject2, subject3 Roll 2 | subject2, subject3
Upvotes: 2
Reputation: 18106
To achieve the desired dictionary it is necessary to create an associative storage for subjects. Please take a look at the code.
Student st1 = new Student
{
Name = "John",
RollNo = "Roll 1"
};
Subject sb1 = new Subject
{
Code = "Subject 1"
};
Subject sb2 = new Subject
{
Code = "Subject 2"
};
Subject sb3 = new Subject
{
Code = "Subject 3"
};
// Create the associative dictionary for subjects.
var subjectsByCode = new [] { sb1, sb2, sb3 }.ToDictionary(subject => subject.Code, subject => subject);
// Many-to-many relationship: Student (RollNo) <=> Subject (Code).
List<KeyValuePair<string,string>> roleList = new List<KeyValuePair<string,string>>
{
new KeyValuePair<string, string>(st1.RollNo, sb1.Code),
new KeyValuePair<string, string>(st1.RollNo, sb2.Code),
new KeyValuePair<string, string>(st1.RollNo, sb3.Code)
};
// Create Student RollNo => List of Subjects dictionary.
Dictionary<string, List<Subject>> studentRollNoToSubjects = roleList
.GroupBy(pair => pair.Key) // Group by RollNo
.ToDictionary(group => group.Key, // Key of the dictionary is RollNo.
group => group.Select(pair => subjectsByCode[pair.Value]).ToList()); // List of subjects is created using subjects-by-code dictionary.
Upvotes: 2
Reputation: 54887
Your question isn’t really clear. If you’re asking for an example of how to populate your dictionary, here’s one:
Dictionary<string, List<Subject>> stSbList = new Dictionary<string, List<Subject>>();
stSbList.Add(st1.RollNo, new List<Subject> { sb1, sb2, sb3 });
stSbList.Add(st2.RollNo, new List<Subject> { sb1, sb3 });
stSbList.Add(st3.RollNo, new List<Subject> { sb1, sb2 });
More succinctly using nested collection initializers:
Dictionary<string, List<Subject>> stSbList = new Dictionary<string, List<Subject>>
{
{ st1.RollNo, new List<Subject> { sb1, sb2, sb3 } },
{ st2.RollNo, new List<Subject> { sb1, sb3 } },
{ st3.RollNo, new List<Subject> { sb1, sb2 } },
};
Update: As others have pointed out, your definition of RoleList
as a dictionary is probably erroneous, since it will not allow you to define multiple subjects for the same student. What you need is a data structure that supports the representation of a many-to-many relation; for example, a List<T>
of Tuple<string,string>
, where Item1
of each tuple contains the Student.RollNo
, whilst Item2
contains the Subject.Code
:
var roleList = new List<Tuple<string, string>>();
roleList.Add(Tuple.Create(st1.RollNo, sb1.Code));
roleList.Add(Tuple.Create(st1.RollNo, sb2.Code));
roleList.Add(Tuple.Create(st1.RollNo, sb3.Code));
roleList.Add(Tuple.Create(st2.RollNo, sb1.Code));
roleList.Add(Tuple.Create(st2.RollNo, sb3.Code));
roleList.Add(Tuple.Create(st3.RollNo, sb1.Code));
roleList.Add(Tuple.Create(st3.RollNo, sb2.Code));
To convert this into a dictionary, you could use first use the GroupBy
operator, followed by ToDictionary
:
var subjects = new[] { sb1, sb2, sb3 }.ToDictionary(sb => sb.Code);
Dictionary<string, List<Subject>> stSbList =
roleList.GroupBy(tuple => tuple.Item1)
.ToDictionary(
grouping => grouping.Key,
grouping => grouping.Select(tuple => subjects[tuple.Item2]).ToList(),
EqualityComparer<string>.Default);
Update2: For completeness, this is how to construct the dictionary from your definition of RoleList
(although this probably isn’t what you want):
var roleList = new Dictionary<string, string>();
roleList.Add(st1.RollNo, sb1.Code);
roleList.Add(st2.RollNo, sb2.Code);
roleList.Add(st3.RollNo, sb2.Code);
var subjects = new[] { sb1, sb2, sb3 }.ToDictionary(sb => sb.Code);
Dictionary<string, List<Subject>> stSbList = roleList.ToDictionary(
kvp => kvp.Key,
kvp => new List<Subject> { subjects[kvp.Value] });
Update3: Adapted to work with the latest version of your code:
var subjects = new[] { sb1, sb2, sb3 }.ToDictionary(sb => sb.Code);
Dictionary<string, List<Subject>> stSbList =
RoleList.GroupBy(kvp => kvp.Key)
.ToDictionary(
grouping => grouping.Key,
grouping => grouping.Select(kvp => subjects[kvp.Value]).ToList());
Upvotes: 3