Sort list based on group count

前端 未结 3 650
忘掉有多难
忘掉有多难 2020-12-21 03:41

I\'d like to sort a List on element counts of IGroupings.

And that\'s it, the list should ideally be the same. I would compromise

相关标签:
3条回答
  • 2020-12-21 04:11

    Almost no operation in .NET clones an object. Neither deeply nor shallowly. LINQ also does not clone the elements it processes. Therefore, a simple LINQ query will work:

    var oldList = ...;
    var newList = (from x in oldList
                   group x by something into g
                   orderby g.Count()
                   from x in g //flatten the groups
                   select x).ToList();
    

    This code copies references to the original objects. If you believe otherwise, you are probably misinterpreting what you are seeing.

    0 讨论(0)
  • 2020-12-21 04:14

    Well, this is embarrassing.

    My mistake was indeed based on a misunderstanding:

    class Item
    {
        internal string Value { get; set; }
        internal string Qux { get; set; }
        internal string Quux { get; set; }
    }
    
    var query = from i in list
                group i by new { i.Value, i.Qux } into g // Note: no Quux, no primary key, just what's necessary
                orderby g.Count() descending, g.Key.Value
                select new { // [1]
                    Value = g.Key.Value,
                    Qux = g.Key.Qux,
                    // Quux?
                }
    

    My bad assumption was that the selection at [1] was acting on individual records, much like SQL. Well, hopefully I can save someone who had the same assumption: it is not.

    It seems obvious now, but the selection acts on individual groups, and hence here a new object would be created for each group, not for each element.

    My second mistake was in focusing on the key, wondering how one would "pass" other properties without using it. I was also worried that we seemed to be required to make shallow copies of our objects. Again this is based on the fact that we were clueless as to how the IGrouping is behaving: since we didn't know we were selecting on the groups, we couldn't even create new objects for each element from the select.

    The solution is definitely not impressive:

    var query = from i in list
                group i by new { i.Value, i.Qux } into g
                orderby g.Count() descending, g.Key.Value
                select g;
    
    foreach (var group in query)
    {
        foreach (var item in group)
            Console.WriteLine("{0} {1} {2} [Original object? {3}]",
                item.Value,
                item.Qux,
                item.Quux,
                list.Contains(item));
    
        Console.WriteLine("-");
    }
    

    Output:

    AAA Foo ... [Original object? True]
    AAA Foo ... [Original object? True]
    AAA Foo ... [Original object? True]
    -
    BBB Foo ... [Original object? True]
    BBB Foo ... [Original object? True]
    -
    AAA Bar ... [Original object? True]
    -
    CCC Foo ... [Original object? True]
    -
    DDD Foo ... [Original object? True]
    -
    DDD Bar ... [Original object? True]
    -
    EEE Foo ... [Original object? True]
    

    Indeed the IGrouping elements are the original elements. From there we can create a new list without any issue.

    Update: I flatten the result set outside of the query mainly to be able to write the group separator to the console for demonstration purposes, but see Tim's and usr's answers to flatten inside the query using SelectMany (and equivalent Linq syntax).

    Needless to say, this was another classic case of "we're in too much of a hurry, let's read some examples here and there and that'll be it", where the proper approach would have been to spend a little bit of time learning the fundamentals. Linq is not SQL.

    My apologies for the time you may have wasted trying to clear the confusion. Hopefully someone else in a hurry might benefit from these mistakes now.

    0 讨论(0)
  • 2020-12-21 04:18
    var mySortedList = myList.GroupBy(x => x.Name).OrderByDescending(g => g.Count())
                           .SelectMany(x => x).ToList();
    
    0 讨论(0)
提交回复
热议问题