Как сделать мультисортировку списка объектов на основе заданных настроек? - PullRequest
0 голосов
/ 08 июня 2019

Цель: у вас есть список объектов, вы хотите, чтобы конечный пользователь мог выбрать некоторые свойства объектов для определения сортировки и выбрать направление сортировки для каждого свойства.

Давайте возьмем этот объект Node какНапример:

    public class Node
    {
        public int CustomProperty { get; set; }
        public string CustomStringProperty { get; set; }

        public string id;
        public string parentId;
        public string Speed;
        public int WheelNumber;
        public int SeatNumber;

        public List<Node> Child { get; set; }

        public Node()
        {
            Child = new List<Node>();
        }
    }

Допустим, у вас есть список узлов, которые вы хотите отсортировать на основе таких критериев, как скорость, номер колеса или номер места.

Вы будете использовать любой .OrderBy,.ThenByDescending и т. Д. В зависимости от цели, но проблема в том, что она жестко запрограммирована, поэтому разработчик в настоящее время управляет кодом;конечный пользователь не будет погружаться в код, тем более каждый раз, когда ему нужно изменить коллекцию критериев для сортировки и определить направление для каждого критерия (свойство объекта).

Вы можете использовать некоторый код, помогающий пользователю определитьпредпочтения, что-то вроде этого:

public static List<Node> Sort(List<Node> nodes, int level, string[] sortingPreferences)
    {
        // Recursively sort nodes children
        foreach (var node in nodes)
            node.Child = Sort(node.Child, level + 1, sortingPreferences);

           // Now sort the nodes based on preference
            if (nodes.Count < 2) return nodes;

            if (level < sortingPreferences.Length)
            {
                switch (sortingPreferences[level])
                {
                    case "SPEED": return nodes.OrderBy(node => node.Speed).ToList();
                    case "WHEEL_NUMBER": return nodes.OrderBy(node => node.WheelNumber).ToList();
                    case "SEAT_NUMBER": return nodes.OrderBy(node => node.SeatNumber).ToList();
                    case "SPEED - WHEEL_NUMBER": return nodes.OrderBy(node => node.Speed).ThenBy(node => node.WheelNumber).ToList();
                    case "SPEED - WHEEL_NUMBER - SEAT_NUMBER": return nodes.OrderBy(node => node.Speed).ThenBy(node => node.WheelNumber).ThenByDescending(node => node.SeatNumber).ToList();
                    // And so on...
                    // And so on...
                }
            }
            // Unchanged (or nodes.OrderBy(some default order)
            return nodes;
    }

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

Вопрос: Как определить некоторые параметры / предпочтения сортировки, в которых критерии (скорость, номер колеса, номер места ...) будутбыть применены вместе с соответствующим направлением сортировки к списку объектов для его мультисортировки?

Я имею в виду, например, предпочтения могут быть заданы следующим образом:

        new List<string>[]
                    {
                       new List<string>{ "SPEED", "ASCENDING" },           
                       new List<string>{ "WHEEL_NUMBER", "DESCENDING" },           
                       new List<string>{ "SEAT_NUMBER", "DESCENDING" },
                    },

Здесь у вас есть3 критерия, но конечный пользователь через графический интерфейс может добавить еще несколько и выбрать направление для каждого из них.

Тогда как учесть эти предпочтения, чтобы применить их в списке объектов?

Ответы [ 2 ]

2 голосов
/ 08 июня 2019

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

var map = new Dictionary<string,Func<Node,IComparable>>
{
    { "PropertyA", node => node.PropertyA },
    { "PropertyB", node => node.PropertyB }
};

Затем поместите ключи сортировки в массив:

var sortBy = new string[] { "PropertyA", "PropertyB" };

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

foreach (var sortKey in sortBy.Reverse())
{
    list = list.OrderBy( map[sortKey] );
}

Вот как это выглядит в контексте с тестовыми данными:

var map = new Dictionary<string,Func<Node,IComparable>>
{
    { "PropertyA", node => node.PropertyA },
    { "PropertyB", node => node.PropertyB }
};

IEnumerable<Node> list = new Node[]
{
    new Node { PropertyA = 1, PropertyB = "Z" },
    new Node { PropertyA = 2, PropertyB = "A" },
    new Node { PropertyA = 2, PropertyB = "B" }
};


var sortBy = new string[] { "PropertyA", "PropertyB" };

foreach (var sortKey in sortBy.Reverse())
{
    list = list.OrderBy( map[sortKey] );
}

foreach (var node in list)
{
    Console.WriteLine("{0} {1}", node.PropertyA, node.PropertyB);
}

Выход:

1 Z
2 A
2 B

Рабочий пример для DotNetFiddle

0 голосов
/ 08 июня 2019

Оберните ваши OrderBy вызовы в ICommands (шаблон команды). Сначала вы создаете очередь команд, в которой каждая команда возвращает коллекцию, а затем зацикливаетесь на очереди команд. Если ваш ввод изменяется, commandslist необходимо перестроить.

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

Редактировать: вы можете использовать c # Func для команд и очереди сортировки пар по значению ключа enum и Func.

Func<List<T>,List<T>> например и Queue<KeyValuePair<SortEnum,Func<List<T>,List<T>>>

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...