Сортировка клавиш оператора LINQ 'GroupBy' в произвольном порядке - PullRequest
2 голосов
/ 22 апреля 2020

В c#, при использовании оператора LINQ 'GroupBy', я бы хотел отсортировать ключи в указанном порядке.

Мой сценарий основан на футболе, и я хочу отсортировать игроков по заранее определенной позиции (созданной и установленной в CMS). Позиции, которые могут быть назначены игроку, следующие, и они могут быть сгруппированы только в одного

  • вратаря
  • защитника
  • полузащитника
  • нападающего

Player.cs (вниз)

    public string Name {get; set;}
    public string ImgUrl {get; set;}
    public string Position {get; set;}

PlayersLandingPageViewModel.cs (вниз)

    public IEnumerable<IGrouping<string, TeamPlayerPage>> GroupedPlayersList { get; set; }

PlayersLandingPageController (вниз)

    var groupedPlayersList = teamPlayersLandingPage.Children<TeamPlayerPage>().GroupBy(x => x.Position);

    var playersLandingPageViewModel = new PlayersLandingPageViewModel(model.Content)
    {
        GroupedPlayersList = groupedPlayersList
    };

Вышеприведенный код возвращает IEnumerable<IGrouping<string, TeamPlayerPage>>, но ключи расположены в следующем порядке (предполагается, что по умолчанию используется алфавит?) В представлении я просто перебираю каждую группу (ключ) в Model.GroupedPlayersList, а затем всех игроков в группе. Foreach внутри foreach (это работает как ожидалось)

  • защитник
  • вратарь
  • полузащитник
  • нападающий

При поиске решения в следующем посте ( как создать программный порядок сортировки в C# для сгруппированной коллекции ) предлагается использовать IComparer<String>, но из-за отсутствия понимания я Немного неуверенный, как применить это, чтобы работать для моего сценария. Это до, с или после действия GroupBy?

List<string> playerGroupsSortOrder = new List<string>() { "goalkeeper", "defender", "midfielder", "striker"};

Может кто-нибудь что-нибудь порекомендовать? Объяснение или ссылки, которые помогут мне понять любое рабочее решение, было бы очень полезно.

другие ссылки

Спасибо

Ответы [ 4 ]

4 голосов
/ 22 апреля 2020

Если я вас правильно понял, вы можете попробовать mapping : при сортировке вы можете вычислить требуемый порядок (скажем, 0, 1, 2, 3) для каждого Key («нападающий», "защитник" и т. д. c.), т. е. сопоставление Key с требуемым порядком.

  List<string> playerGroupsSortOrder = new List<string>() { 
    "goalkeeper", "defender", "midfielder", "striker"
  };

  ...

  var groupedPlayersList = teamPlayersLandingPage
    .Children<TeamPlayerPage>()
    .GroupBy(x => x.Position)
    .OrderBy(group => playerGroupsSortOrder.IndexOf(group.Key));
4 голосов
/ 22 апреля 2020

Поскольку у позиции есть конечное число возможных значений, enum кажется лучшим вариантом, чем строка:

enum Position
{
    Goalkeeper,
    Defender,
    Midfielder,
    Striker
}

Тогда, поскольку перечисления являются просто целыми числами, у вас есть ваш заказ. Вратарь = 0, Защитник = 1 и c.

Обновите свой класс:

public Position Position { get; set; }

Затем LINQ:

teamPlayersLandingPage
    .Children<TeamPlayerPage>()
    .GroupBy(x => x.Position)
    .OrderBy(grp => (int)grp.Key);
2 голосов
/ 22 апреля 2020

Вы можете использовать enum для позиции игрока вместо строк, поэтому под капотом они будут рассматриваться как int.

public enum PlayerPosition
{
    goalkeeper, defender, midfielder, striker
}

Когда я попробовал это в консольном приложении, казалось, что работать, если вы выполняете заказ до запуска группы по.

var players = new List<Player>
        {
            new Player { Name = "A", Position = PlayerPosition.midfielder },
            new Player { Name = "B", Position = PlayerPosition.goalkeeper },
            new Player { Name = "C", Position = PlayerPosition.defender },
            new Player { Name = "D", Position = PlayerPosition.midfielder },
            new Player { Name = "E", Position = PlayerPosition.striker },
        };

var result = players.OrderBy(x => x.Position).GroupBy(x => x.Position);
1 голос
/ 22 апреля 2020

Вы можете создать Dictionary<string, int> ордеров позиции из playerGroupsSortOrder, затем сгруппировать и отсортировать список игроков, используя этот словарь поиска для O (1) поисков:

var playerGroupsSortOrder = new List<string>() 
{ 
    "goalkeeper", 
    "defender", 
    "midfielder", 
    "striker" 
};

// Create this lookup dictionary here
var playerPositionOrder = playerGroupsSortOrder
    .Select((pos, index) => (pos, index))
    .ToDictionary(kvp => kvp.pos, kvp => kvp.index);

var sortedGroupPlayerList = teamPlayersLandingPage
    .Children<TeamPlayerPage>()
    .GroupBy(x => x.Position)
    .OrderBy(group => playerPositionOrder[group.Key]);

Или просто иметь этот словарь для начала:

var playerPositionOrder = new Dictionary<string, int>
{
    { "goalkeeper", 0 },
    { "defender", 1 },
    { "midfielder", 2 },
    { "striker", 3 }
};

var sortedGroupPlayerList = teamPlayersLandingPage
    .Children<TeamPlayerPage>()
    .GroupBy(x => x.Position)
    .OrderBy(group => playerPositionOrder[group.Key]);
...