5

I have an oject of the type IGrouping and would like to order the elements inside the group without changing the type of the object.
In other words, I have

var tmp = group.OrderBy(x => x);

with group being of type IGrouping<int, someanonymousclass> and I want tmp to be of type IGrouping<int, someanonymousclass> as well.

One workaround would be to change it to a Dictionary or a new anonymous class, but I want tmp to specificly be of type IGrouping<int, someanonymousclass>.

In other words: I want to sort the elemnts of my IGrouping<int, someanonymousclass> object. If I use OrderBy it changes the type of group to IOrderedEnumerable and I cannot access group.Key anymore. How can i sustain the type of group?

Example:

var states = SimulationPanel.innerPanel.Children.OfType<StateBar>().Where(x => x.isSensorState())
                .GroupBy(x => (SensorElement)x.BauplanElement,
                         x => new
                         {
                             Start = (decimal)(x.Margin.Left / SimulationPanel.Zoom),
                             Width = (decimal)(x.Width / SimulationPanel.Zoom),
                             State = x.State
                         });

var group = states.First();
var tmp = group.OrderBy(x => x.Start);
var key = tmp.Key;    //This does not work, because tmp is not of type IGrouping

I know I could use OrderBy before grouping. I don't want to do that, though.

Tim Pohlmann
  • 4,140
  • 3
  • 32
  • 61
  • 1
    I'm finding it hard to understand your question based only on the description - could you give a short but complete description? – Jon Skeet Jul 08 '15 at 08:21
  • can you provide input/output sample of what you are looking for? – Hossein Narimani Rad Jul 08 '15 at 08:23
  • @JonSkeet What exactly are you not understanding? As a result I want an object of type `IGrouping` but its elements should be ordered. – Tim Pohlmann Jul 08 '15 at 08:23
  • @TimPohlmann: It's the "typeof(x)" part which is very confusing. Also you talk about `IGrouping` as if it's a non-generic type, which it isn't... basically, an example would help a *lot*, and make it much easier to validate any answers. – Jon Skeet Jul 08 '15 at 08:27
  • @JonSkeet I wrote `typeof(x)` because x is type of an anonymous class, which I cannot reference at compile time. I tried to clarify the question a bit with an edit. – Tim Pohlmann Jul 08 '15 at 08:30
  • Again, an *example* would be the best form of clarification... – Jon Skeet Jul 08 '15 at 08:34
  • @HosseinNarimaniRad I updated the question and fixed the generics. Do you now understand what I'm looking for? – Tim Pohlmann Jul 08 '15 at 08:34
  • @JonSkeet added an example, hope that helps. – Tim Pohlmann Jul 08 '15 at 08:41
  • 1
    Yes, it does, definitely. Next time you ask, please consider including an example sooner rather than later. Will see what I can do to answer... – Jon Skeet Jul 08 '15 at 08:42

1 Answers1

16

If you can, just put the ordering earlier, e.g.

var states = SimulationPanel.innerPanel
       .Children
       .OfType<StateBar>()
       .Where(x => x.isSensorState())
       .OrderBy(x => (decimal)(x.Margin.Left / SimulationPanel.Zoom))
       .GroupBy(...);

(Or put a Select before the OrderBy and make the GroupBy simpler.)

If you really need this though, you could write your own IGrouping<TKey, TElement> implementation and an extension method to order the elements and retain them in a list:

public static class GroupExtensions
{
    public static IGrouping<TKey, TElement> OrderGroupingBy<TKey, TElement, TOrderKey>
        (this IGrouping<TKey, TElement> grouping,
         Func<TElement, TOrderKey> orderKeySelector)
    {
        return new GroupingImpl<TKey, TElement>
            (grouping.Key, grouping.OrderBy(orderKeySelector));
    }

    private class GroupingImpl<TKey, TElement> : IGrouping<TKey, TElement>
    {
        private readonly TKey key;
        private readonly List<TElement> elements;

        internal GroupingImpl(TKey key, IEnumerable<TElement> elements)
        {
            this.key = key;
            this.elements = elements.ToList();
        }

        public TKey Key { get { return key; } }

        public IEnumerator<TElement> GetEnumerator()
        {
            return elements.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }
}
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • What exactly do you mean with "Or put a Select before the OrderBy and make the GroupBy simpler."? – Tim Pohlmann Jul 08 '15 at 08:55
  • 2
    @TimPohlmann: Well currently you're transforming within your `GroupBy`. If you transform earlier than that, you could avoid duplicating the code that is reflected in the `Start` property, for the ordering. – Jon Skeet Jul 08 '15 at 08:57
  • @JonSkeet The code in the second code block [didn't compile](https://stackoverflow.com/posts/74414995/timeline#comment_131367696). I'm assuming you just posted it as pseudocode to illustrate the idea but you didn't test it at the time. I edited the code to what I think you actually intended. Please let me know if I was wrong about that. – 41686d6564 stands w. Palestine Nov 12 '22 at 18:07
  • 1
    @41686d6564standsw.Palestine: I've removed the `AsEnumerable()` but renamed the method to avoid ambiguity/recursion; but thanks for fixing it to compile – Jon Skeet Nov 12 '22 at 20:09