Сортировка списка <T>на основе свойства T's List <string> - PullRequest
0 голосов
/ 08 февраля 2019

У меня есть пользовательский объект Deck, у которого List<Card> cards между его свойствами.Каждый Card имеет свой собственный List<string> colors, обозначающий цвет карты с использованием одной или нескольких заглавных букв, например [W, U, B, R, G].

. Мне нужно отсортировать список cards на основе colors перечислить так, чтобы я сначала получил все карты одного цвета и т. Д. Для каждого цвета;с картами, имеющими более одного цвета, я бы хотел, чтобы они сортировались на основе пользовательского списка приоритетов (например, если это W и U, поместите его между W картами), но я понимаю, что это еще более сложно, так что это не такдействительно необходимость для меня.

Я пытался сделать

deck.cards = deck.cards.OrderBy(x => x.colors).ToList();

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

Чтоя могу сделать, чтобы отсортировать мой список колод?Можно ли не только отсортировать, как описано, но и на основе определенного порядка, например, B до R до G и т. Д.

Ответы [ 2 ]

0 голосов
/ 08 февраля 2019

Вы можете получить список заказанных карточек, используя функцию агрегирования следующим образом:

var result = deck.Cards
    .OrderBy(x => x.Colours.Aggregate((total, part) => total + part.ToLower()))
    .ToList();

Это предполагает, что карточки с несколькими цветами имеют те, которые есть в упорядоченном списке.

например

    card1.Colours = new List<string>() { "W", "X" };
    card2.Colours = new List<string>() { "W" };
    card3.Colours = new List<string>() { "U" };
    card4.Colours = new List<string>() { "U", "W" };

Вернет карточки в следующем порядке:

"U", "UW", "W", "WX"

0 голосов
/ 08 февраля 2019

На основании обсуждения в комментариях, когда карта имеет несколько цветов, вы хотите выбрать один цвет (тот, который появляется первым в списке приоритетов) и отсортировать его на этом основании.

// Higher-priority colours come first
var coloursPriority = new List<string>() { "W", "U", "B", "R", "G" };

// Turn the card's colour into an index. If the card has multiple colours,
// pick the smallest of the corresponding indexes.
cards.OrderBy(card => card.Colours.Select(colour => coloursPriority.IndexOf(colour)).Min());

Отвечая на обсуждение в комментариях: если вы хотите отсортировать карточки сначала по цвету с наивысшим приоритетом, , а затем по цвету с наивысшим приоритетом и т. Д., То этодостаточно эффективный способ сделать это:

public class CardColourComparer : IComparer<List<int>>
{
    public static readonly CardColourComparer Instance = new CardColourComparer();
    private CardColourComparer() { }

    public int Compare(List<int> x, List<int> y)
    {
        // Exercise for the reader: null handling

        // For each list, compare elements. The lowest element wins
        for (int i = 0; i < Math.Min(x.Count, y.Count); i++)
        {
            int result = x[i].CompareTo(y[i]);
            if (result != 0)
            {
                return result;
            }
        }

        // If we're here, then either both lists are identical, or one is shorter, but it
        // has the same elements as the longer one.
        // In this case, the shorter list wins
        return x.Count.CompareTo(y.Count);
    }
}

Тогда

// Higher-priority colours come first
var coloursPriority = new List<string>() { "W", "U", "B", "R", "G" };

cards.OrderBy(card =>
    card.Colours.Select(colour => coloursPriority.IndexOf(colour)).OrderBy(x => x).ToList(),
    CardColourComparer.Instance);

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

Обратите внимание, что это не заботится о порядке цветов, связанных с каждой картой: [W, U] будет сортировать так же, как [U, W].Чтобы принять во внимание заказ (например, [W] предшествует [W, U] до [U, W], сделайте следующее:

cards.OrderBy(card =>
    card.Colours.Select(colour => coloursPriority.IndexOf(colour)).ToList(),
    CardColourComparer.Instance);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...