我需要一些关于LINQ的Group By的理解帮助。

huangapple go评论70阅读模式
英文:

I need some help understanding LINQ group by

问题

Here's the translated code part you requested:

假设我有一个类

```csharp
public class Movie
{
    public string Title { get; set; }
    public string Genre { get; set; }
    public int Rating { get; set; }
}

和一个电影文本文件,它将被解析为一个 List<Movie>

The_Godfather 动作 96
The_Dark_Knight 戏剧 24
Cleopatra 喜剧 61
Sabotage 动作 88
Inception 戏剧 86
The_Matrix 喜剧 14
Life_Is_Beautiful 戏剧 19
City_of_God 恐怖 12
Raven 喜剧 30
Breaking_Wind 喜剧 59
City_Lights 纪录片 46
Born_Wild 戏剧 55

和一个函数

public static Dictionary<string, Movie> HighestRatingForEachGenre(List<Movie> movies)

我想要按流派分组,然后为每个流派返回标题和电影对象。

我可以轻松地使用 foreach 循环来完成这个任务。

我对 LINQ 还不太熟悉,不知道从哪里开始。

基本方法如下:

Dictionary<string, Movie> result = new Dictionary<string, Movie>();
foreach (Movie movie in movies)
{
    if (result.ContainsKey(movie.Genre))
    {
        if (result[movie.Genre].Rating < movie.Rating) result.Remove(movie.Genre);
        else continue;
    }
    result.Add(movie.Genre, movie);
}
return result;

<details>
<summary>英文:</summary>

Suppose I have a class 

public class Movie
{
public string Title { get; set; }
public string Genre { get; set; }
public int Rating { get; set; }
}

and a text file of movies, that&#39;ll be parse into a list&lt;Movie&gt;

The_Godfather Action 96
The_Dark_Knight Drama 24
Cleopatra Comedy 61
Sabotage Action 88
Inception Drama 86
The_Matrix Comedy 14
Life_Is_Beautiful Drama 19
City_of_God Horror 12
Raven Comedy 30
Breaking_Wind Comedy 59
City_Lights Documentary 46
Born_Wild Drama 55

and a function 

public static Dictionary<string, Movie> HighestRatingForEachGenre(List<Movie> movies)

&lt;strike&gt;I want to return the highest rating for each genre using LINQ.&lt;/strike&gt; 

I want to group by genre then return a title and movie object for each genre.

I could do this with a foreach loop easily.
 
I&#39;m still new to LINQ and have no idea where to look. 


basic approach
        Dictionary&lt;string, Movie&gt; result = new Dictionary&lt;string, Movie&gt;();
        foreach (Movie movie in movies)
        {
            if (result.ContainsKey(movie.Genre))
            {
                if (result[movie.Genre].Rating &lt; movie.Rating) result.Remove(movie.Genre);
                else continue;
            }
            result.Add(movie.Genre, movie);
        }
        return result;


</details>


# 答案1
**得分**: 2

为了获得您期望的结果,您的LINQ表达式需要依次执行三个操作:

1. 按类型对电影进行分组
2. 从每个组中提取最高评分的电影
3. 将结果集映射到一个字典中

第一步是按类型对电影进行分组,可以使用 `movies.GroupBy(m => m.Genre)` 完成。这将生成一个组的集合,每个组都有 (1) 一个共同的类型作为键 和 (2) 一个包含共同类型的电影的集合。`m => m.Genre` 部分是一个 *lambda函数*,选择了定义所需分组的属性。

接下来,在每个组内,您希望选择评分最高的电影。可以通过结合使用 `Select(...)`, `.OrderBy(...)` 和 `.First()` 来完成,如 `.Select(grp => grp.OrderByDescending(m => m.Rating).First())`。

最后,`.ToDictionary(...)` 可以构建结果的字典,指定 `m => m.Genre` 作为字典键选择器。

将所有这些组合在一起如下:

```csharp
var highestRatingForEachGenre = movies
    .GroupBy(m => m.Genre)
    .Select(grp => grp.OrderByDescending(m => m.Rating).First())
    .ToDictionary(m => m.Genre);

(最后两行实际上可以在 .ToDictionary() 函数的一个更高级的形式中合并,但我认为将它们作为单独的步骤更容易阅读和理解。)

以上使用了LINQ的方法语法来执行操作。也可以使用LINQ的查询语法来完成相同的操作。(由于我很少使用查询语法,所以无法立即提供一个快速的示例。)

我建议您阅读每个使用的方法的文档,以便了解上述操作的工作原理。

英文:

To get your desired results, your LINQ expression needs to do three things in succession:

  1. Group the movies by Genre
  2. Extract the top movie from each group
  3. Map the resulting collection to a dictionary.

The first step is to group the movies by Genre, which can be done with movies.GroupBy(m =&gt; m.Genre). This will yield a collection of groups, where each group has (1) Key = the common Genre and (2) a collection of movies sharing that Genre. The m =&gt; m.Genre part is a lambda function that selects which property defines the desired groupings.

Next, within each group, you want to select to top rated movie. This can be done with a combination of Select(...), .OrderBy(...), and .First(). as in .Select(grp =&gt; grp.OrderByDescending(m =&gt; m.Rating).First()).

Finally, .ToDictionary(...) can build a dictionary of the results, specifying m =&gt; m.Genre as the dictionary key selector.

Putting all that together gives:

var highestRatingForEachGenre = movies
    .GroupBy(m =&gt; m.Genre)
    .Select(grp =&gt; grp.OrderByDescending(m =&gt; m.Rating).First())
    .ToDictionary(m =&gt; m.Genre);

(The last two lines can actually be combined in a more advanced form of the .ToDictionary() function, but I believe separate steps is easier to read and understand.)

The above uses LINQ method syntax to perform the operations. The same can also be done using LINQ query syntax. (I much less often so can't provide a quick example off the top of my head.)

I suggest that you read the documentation for each method used so that you understand how the above works.

答案2

得分: 1

GroupBy 返回一个由分组组成的 IEnumerable&lt;T&gt;。每个分组本身是一个包含在该分组中的元素的 IEnumerable&lt;T&gt;,而每个分组还具有一个 Key - 用于标识每个分组的值。这是您进行分组的属性。

可通过使用 ToDictionary 将可枚举的分组序列转换为所需的字典,其中分组的键是键,而具有最高评分的电影是值。要获取具有最高评分的电影,您可以在 .NET 6+ 中使用 MaxBy

Dictionary&lt;string, Movie&gt; HighestRatingForEachGenre(List&lt;Movie&gt; movies) =>
    return movies.GroupBy(x => x.Genre)
               .ToDictionary(
                   g => g.Key, // 字典的键是分组的键
                   g => g.MaxBy(m => m.Rating) // 字典的值按此计算
               );
英文:

GroupBy returns an IEnumerable&lt;T&gt; of the groups. Each group is itself an IEnumerable&lt;T&gt; of the elements in the group, and each group also has a Key - the value that identifies each group. This is the property by which you are doing the grouping.

The enumerable sequence of groups can be turned into the dictionary you want by using ToDictionary, with the group's key as the key, and the movie with the maximum rating in that group. To get the movie with the maximum rating, you can use MaxBy in .NET 6+.

Dictionary&lt;string, Movie&gt; HighestRatingForEachGenre(List&lt;Movie&gt; movies) =&gt;
    return movies.GroupBy(x =&gt; x.Genre)
               .ToDictionary(
                   g =&gt; g.Key, // dictionary&#39;s key is the group&#39;s key
                   g =&gt; g.MaxBy(m =&gt; m.Rating) // dictionary&#39;s value is computed like this
               );

答案3

得分: -1

我会稍微修改@T N的答案:

var 每个类型的最高评分 = 电影.GroupBy(s => s.类型).Select(s => new
{
    s.Key,
    最高评分 = s.Max(r => r.评分)
}).ToDictionary(s => s.Key, s => s.最高评分);

foreach (var 电影 in x)
{
    Console.WriteLine($"在{电影.Key}中最高评分是{电影.Value}");
}

OrderByFirst合并为单个Max调用。

英文:

I would tweak @T N's answer just a little bit:

var highestRatingForEachGenre  = movies.GroupBy(s =&gt; s.Genre).Select(s =&gt; new
{
    s.Key,
    MaxRating = s.Max(r =&gt; r.Rating)
}).ToDictionary(s =&gt; s.Key, s =&gt; s.MaxRating);

foreach (var movie in x)
{
    Console.WriteLine($&quot;Highest rating in {movie.Key} is {movie.Value}&quot; );
}

combining OrderBy and First into a single Max call

huangapple
  • 本文由 发表于 2023年6月29日 11:09:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/76577839.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定