Click here to Skip to main content
Rate this: bad
good
Please Sign up or sign in to vote.
Hi,
I am trying to run a linq query on a collection and I want the result to contain all the columns in the collection. But those columns that are not unique across a single rows' aggregation should have the value as null. How can i do this? Is there any expression available using which I can return all such columns for a row (apart from the ones participating in aggregation) which are unique for that aggregated row.

eg:

1) The Class:
public class Person
{ 
string Name 
string Sex
int Age
}



2) The collection:
List<Person> personList


3) Sample data in collection:

 
Name    Sex       Age
----------------------
Rob     Male       25
Bob     Male       25
Kim     Female     22
Debbie  Female     22
----------------------
 
var result = from p in personList 
                  group p by new {p.Sex} into g
                  select new {g.Key.Sex, ???????}
 
I want to be able to get the anonymous result as follows:
 
Sex       Age                                    Name
-----------------------------------------------------------------------------------
Male      25(As 25 is unique across Males)       Null (As Name is not unique across Males)
Female    22(As 22 is unique across Females)     Null 
-----------------------------------------------------------------------------------
 
Does anyone have a way to be able to do this?
Posted 17-Nov-08 3:16am
Edited 3-Jan-12 4:04am
v2
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 1

This may be difficult to add a lot of properties, but this should work for your specific example.

Dim groups = From g In (From p In personList _
             Group p By p.City Into Group) _
             Let SingleName As Boolean = (From r In g.Group Select r.Name Distinct).Count <= 1 _
             Let SingleAge As Boolean = (From r In g.Group Select r.Age Distinct).Count <= 1 _
             Select New Person() With {.Sex = g.Sex, _
                                       .Name = If(SingleName, g.Group.First.Name, Nothing), _
                                       .Age = If(SingleAge, g.Group.First.Age, Nothing)}
For Each g In groups
    Console.WriteLine("{0}, {1}, {2}", g.Sex, g.Age, g.Name)
Next
  Permalink  
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 2

Upon further consideration, I was able to extract the logic for checking properties for the same value within a group into an extension method. This will simplify the query a little bit.


Dim lcGroups = From g In (From p In personList _
                          Group By p.Sex Into Group) _
               Select New Person() With {.Sex = g.Sex, _
                                         .Name = g.Group.SameOrDefault(Function(p) p.Name), _
                                         .Age = g.Group.SameOrDefault(Function(p) p.Age)}

<System.Runtime.CompilerServices.Extension()> _
Public Function SameOrDefault(Of TInput, TOutput)(ByVal items As IEnumerable(Of TInput), _
                                                  ByVal valueSelector As Func(Of TInput, TOutput)) As TOutput
    Return SameOrDefault(items, valueSelector, EqualityComparer(Of TOutput).Default)
End Function

<System.Runtime.CompilerServices.Extension()> _
Public Function SameOrDefault(Of TInput, TOutput)(ByVal items As IEnumerable(Of TInput), _
                                                  ByVal valueSelector As Func(Of TInput, TOutput), _
                                                  ByVal comparer As IEqualityComparer(Of TOutput)) As TOutput
    If items Is Nothing Then Return Nothing
    If valueSelector Is Nothing Then 
        Throw New ArgumentNullException("valueSelector", "A value selector must be provided.")
    End If
    If comparer Is Nothing Then comparer = EqualityComparer(Of TOutput).Default

    Dim result As TOutput = valueSelector(items.First())
    For Each i In items
        If Not comparer.Equals(result, valueSelector(i)) Then Return Nothing
    Next
    Return result
End Function


The first overload will work for most cases, but if you wanted to compare complex types or use some non-default comparison, such as the magnitude of a vector, the second overload would come in handy.
  Permalink  

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS
0 OriginalGriff 350
1 Jochen Arndt 190
2 Richard MacCutchan 135
3 Sergey Alexandrovich Kryukov 130
4 DamithSL 95
0 OriginalGriff 6,045
1 DamithSL 4,601
2 Maciej Los 4,087
3 Kornfeld Eliyahu Peter 3,480
4 Sergey Alexandrovich Kryukov 3,310


Advertise | Privacy | Mobile
Web01 | 2.8.141220.1 | Last Updated 3 Jan 2012
Copyright © CodeProject, 1999-2014
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100