C#列表-从对象列表创建排名

时间:2019-03-21 16:28:12

标签: c# linq

我在List<Players>中填充了Player个对象,如下所示:

class Player
{
    public string Name
    { get; set; }

    public int Points
    { get; set; }

    public string Rank
    { get; set; }

}

基于Points,我想获得一个这样的分组排序列表:

Rank   Name   Points
1-3.   RRR    10
       CCC    10
       AAA    10
4-5.   YYY    8
       XXX    8
6.     ZZZ    7
7-8.   UUU    5
       QQQ    5

...等等。因此Name不应是排序的必需项。 LINQ有可能吗?

编辑1:

到目前为止,我已经尝试过:

    players.ForEach(x =>
    {
        int cnt = players.Count(y => y.Points == x.Points);
        int ind = players.FindIndex(y => y.Points == x.Points);
        x.Rank = (cnt == 1 ? (ind + 1).ToString() : (ind + 1).ToString() + "-" + (ind + cnt).ToString()) + ".";
    });

这非常混乱,并且期望的结果不是我想要的。得分等于或高于上述分数的每个玩家都应拥有Rank属性empty

编辑2:

更干净的代码可以达到所需的结果,如下所示:

    players.ForEach(x =>
    {
        int cnt = players.Count(y => y.Points == x.Points);
        int ind = players.FindIndex(y => y.Points == x.Points);
        x.Rank = ind != players.IndexOf(x) ? string.Empty : $"{ind + 1}" + (cnt == 1 ? string.Empty : "-" + $"{ind + cnt}") + ".";
    });

2 个答案:

答案 0 :(得分:1)

尝试以下操作:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication106
{
    class Program
    {
         static void Main(string[] args)
        {
             List<Player> players = new List<Player>() {
                 new Player() { Name = "RRR", Points = 10 },
                 new Player() { Name = "CCC", Points = 10 },
                 new Player() { Name = "AAA", Points = 10 },
                 new Player() { Name = "YYY", Points = 8 },
                 new Player() { Name = "XXX", Points = 8 },
                 new Player() { Name = "ZZZ", Points = 7 },
                 new Player() { Name = "UUU", Points = 5 },
                 new Player() { Name = "QQQ", Points = 5 }
             };

             var groups = players.OrderBy(x => x.Points)
                 .Select((x, i) => new { rank = i + 1, player = x })
                 .GroupBy(x => x.player.Points).Select(x => new { rank = x.Min(y => y.rank).ToString() + "-" + x.Max(y => y.rank).ToString(), players = x.ToList()})
                 .ToList();

             foreach (var group in groups)
             {
                 group.players.First().player.Rank = group.rank;

                 //foreach (var player in group.players)
                 //{
                 //    player.player.Rank = group.rank;
                 //}
             }
        }

    }
    class Player
    {
        public string Name
        { get; set; }

        public int Points
        { get; set; }

        public string Rank
        { get; set; }

    }



}

答案 1 :(得分:0)

由于您已经编辑了帖子并显示了解决问题的尝试,因此我们将为您提供帮助。将任何玩家集合传递到此功能中,以按照您要求的格式重新获得玩家的新集合。

注意:此函数修改传入的Player中的IEnumerable<Player>引用。如果由于某种原因您不希望这种行为,只需将Player = player替换为Player = new Player { Name = player.Name, Points = player.Points }复制它们。

using System;
using System.Linq;
using System.Collections.Generic;

public static IEnumerable<Player> GetGroupedPlayers(IEnumerable<Player> players)
{
    return players
    .OrderByDescending(player => player.Points)
    .Select((player, index) =>
    new
    {
        Player = player,
        Rank = ++index
    })
    .GroupBy(container => container.Player.Points)
    .Select(group =>
    {
        var firstPlayer = group.First().Player;
        var groupMin = group.Min(container => container.Rank);
        var groupMax = group.Max(container => container.Rank);
        firstPlayer.Rank = groupMin == groupMax ? $"{groupMin}." : $"{groupMin} - {groupMax}.";
        return group.Select(g => g.Player);
    })
    .SelectMany(player => player);
}

希望有帮助。