Miguel Moura
Miguel Moura

Reputation: 39394

Use SelectMany and GroupBy

The following ProjectEnrolment defines a User in a Project and its Enrolment Type in it:

public class ProjectEnrolment {
  public Project Project { get; set; }
  public User User { get; set; }
  public EnrolmentType EnrolmentType { get; set; }
}

For testing purpose I need to create a list of ProjectEnrolments where:
1. There must be more than one ProjectEnrolment per project;
2. A user cannot appear in a project twice.

I tried the following:

List<ProjectEnrolment> projectEnrolments = 
  projects.SelectMany(x => 
  users.SelectMany(y => 
  enrolmentTypes.Select(z => 
    new ProjectEnrolment {
      EnrolmentType = z,
      Project = x,
      User = y
    })))          
  .GroupBy(u => u.Project)          
  .Select(v => v.OrderBy(w => Guid.NewGuid()).FirstOrDefault())
  .ToList();  

But this gives me one ProjectEnrolment per Project which is not what I need.

Upvotes: 3

Views: 10205

Answers (2)

Diego
Diego

Reputation: 16714

Although it is possible I wouldn't do what you want in a single instruction using SelectMany and other linq methods. It's a quite complex logic and the final instruction wont be readable. How about this:

Random r = new Random();
IList<ProjectEnrolment> projectEnrolments = new List<ProjectEnrolment>();
foreach (Project project in projects)
{
    int firstUser = r.Next(users.Count);
    projectEnrolments.Add(new ProjectEnrolment {
        EnrolmentType = enrolmentTypes[r.Next(enrolmentTypes.Count)],
        Project = project,
        User = users[firstUser]
    });
    int secondUser;
    do {
        secondUser = r.Next(users.Count);
    } while (secondUser == firstUser);
    projectEnrolments.Add(new ProjectEnrolment {
        EnrolmentType = enrolmentTypes[r.Next(enrolmentTypes.Count)],
        Project = project,
        User = users[secondUser]
    });
}

Version using Linq

IList<ProjectEnrolment> projectEnrolments = projects.SelectMany(p => users.OrderBy(u => Guid.NewGuid()).Take(2).Select(u => new ProjectEnrolment {
    EnrolmentType = enrolmentTypes.OrderBy(t => Guid.NewGuid()).FirstOrDefault(),
    Project = p,
    User = u
})).ToList();

Upvotes: 1

Ryan
Ryan

Reputation: 746

You can use this one too.
Here every user will be enrolled for every project with random enrollment type:

 Random rnd = new Random();
 var res = users.SelectMany(u => projects.Select(p => new ProjectEnrolment() {EnrolmentType = enrollmentTypes[rnd.Next(0, 3)], User = u, Project = p}))
.GroupBy(i => i.Project);

Upvotes: 0

Related Questions