bambi
bambi

Reputation: 1179

Grouping list of objects by something other than properties of those objects

How to group list of objects by something other than properties of those objects? I need to group List statistics. Each object in the list has property string Question, and for each Question there are some possible answers by which I want to group the list (each group having same possible answers), but those possible answers are not directly related to Statistics class.

I want to do something like this:

var customGroups = from stat in statistics group stat by new { PossibleAnswers = questions.SingleOrDefault(q => q.Text == stat.Question).PossibleAnswers };
foreach (var group in customGroups)
{
   StatisticsWithSamePossibleAnswers.Add(group.ToList());
}

The code gives runtime exception: Object reference not set to an instance of an object.

So what is good way to do this? I know I can always use nested foreach loops, but is there anything wiser?

Classes Statistics and Question look like:

public class Statistics
{
    public int ID { get; set; }
    public int Year { get; set; }
    public int Semester { get; set; }
    public string Subject { get; set; }
    public string Question { get; set; }
    public bool IsAssociatedWithProfessor { get; set; }
    public bool IsAssociatedWithAssistant { get; set; }
    public string Answer { get; set; }
    public int NumberOfAnswers { get; set; }
    public double AnswerPercentage { get; set; }
    public double? AM { get; set; }
    public double? SD { get; set; }
}
public class Question
{
    public int ID { get; set; }
    public string Text { get; set; }
    public bool IsAssociatedWithProfessor { get; set; }
    public bool IsAssociatedWithAssistant { get; set; }
    public virtual ICollection<PossibleAnswer> PossibleAnswers { get; set; }
    public virtual ICollection<Results> Results { get; set; }
}

Upvotes: 2

Views: 102

Answers (2)

recursive
recursive

Reputation: 86144

HashSet<T> can be grouped using the right equality comparer.

var customGroups = statistics.GroupBy(
    stat => new HashSet<PossibleAnswer>(questions.Single(q => q.Text == stat.Question).PossibleAnswers),
    HashSet<PossibleAnswer>.CreateSetComparer());

Note that this ignores answer order and duplicate answers. This also assumes that PossibleAnswer is equatable by default.

Upvotes: 3

StriplingWarrior
StriplingWarrior

Reputation: 156708

In order to use something as the key in a group by query, it has to be something that can be equality-compared. Lists aren't considered "Equal" just because they have the same values in them, so you'll want to transform the list of possible answers into something more comparable. In the code sample below, I'm using a string.Join() to produce a comma-separated string of the answers, but you can tweak that as necessary.

var customGroups = from stat in statistics 
    group stat by string.Join(", ", 
        from q in questions
        where q.Text == stat.Question
        select q.PossibleAnswers);
foreach (var group in customGroups)
{
   StatisticsWithSamePossibleAnswers.Add(group.ToList());
}

Note also that by getting rid of SingleOrDefault() I avoid the problem you were running into when you hit a stat that had no matching questions, and got a null reference exception. Instead, you should just get an empty string to group by.

Upvotes: 2

Related Questions