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 _<br /> Group By p.Sex Into Group) _<br /> Select New Person() With {.Sex = g.Sex, _<br /> .Name = g.Group.SameOrDefault(Function(p) p.Name), _<br /> .Age = g.Group.SameOrDefault(Function(p) p.Age)}<br /><br /><System.Runtime.CompilerServices.Extension()> _<br />Public Function SameOrDefault(Of TInput, TOutput)(ByVal items As IEnumerable(Of TInput), _<br /> ByVal valueSelector As Func(Of TInput, TOutput)) As TOutput<br /> Return SameOrDefault(items, valueSelector, EqualityComparer(Of TOutput).Default)<br />End Function<br /><br /><System.Runtime.CompilerServices.Extension()> _<br />Public Function SameOrDefault(Of TInput, TOutput)(ByVal items As IEnumerable(Of TInput), _<br /> ByVal valueSelector As Func(Of TInput, TOutput), _<br /> ByVal comparer As IEqualityComparer(Of TOutput)) As TOutput<br /> If items Is Nothing Then Return Nothing<br /> If valueSelector Is Nothing Then <br /> Throw New ArgumentNullException("valueSelector", "A value selector must be provided.")<br /> End If<br /> If comparer Is Nothing Then comparer = EqualityComparer(Of TOutput).Default<br /><br /> Dim result As TOutput = valueSelector(items.First())<br /> For Each i In items<br /> If Not comparer.Equals(result, valueSelector(i)) Then Return Nothing<br /> Next<br /> Return result<br />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.