Как мне сделать мой MergeSort универсальным для разных объектов?

В настоящее время у меня есть сортировка слиянием, которая сортирует список узлов в соответствии с целым числом в каждом узле, называемом «F» (So Node.F).

Однако у меня возникла необходимость использовать MergeSort для другого списка объектов — Entities. Однако я хочу отсортировать это в соответствии с целым числом в каждой сущности с именем «AmountEaten» (So Entity.AmountEaten).

Теперь вот моя проблема -> заставить класс MergeSort работать для всех объектов. Я уже заменил все ссылки на Node в рамках сортировки на «объект», но как разрешить настраиваемые критерии для сортировки? Есть ли способ предоставить его в качестве параметра.

Если это не имеет смысла, в MergeSort я сравниваю два значения (например, Left.F ‹ Right.F). С универсальным объектом это не работает, потому что F не существует. Я хотел бы иметь возможность сравнивать что-либо внутри объекта, внутри моей сортировки (например, Left.AmountEaten ‹ Right.AmountEaten). Я не могу понять, как указать это как параметр. Я сразу подумал о делегатах, но я не уверен, как/правильно ли это.

Поскольку сортировка имеет дело со списками, а не с отдельными объектами, я не могу просто указать параметр F/AmountEaten, поскольку я хотел бы получить доступ к переменной, а не к значению.

Если вам нужна дополнительная информация/не понимаю, пожалуйста, спросите.

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

Класс сортировки слиянием:

static class MergeSort
{
    public static IList<object> Sort(IList<object> input, Comparison<object> comparison /* Comparison is a delegate that works out the difference
                                                                                         * between 2 values - Same signature used by List<T>.Sort */)
    {
        List<object> Result = new List<object>();
        Queue<object> Left = new Queue<object>(); //Switched from lists to queues because removing at index 0 is more efficient
        Queue<object> Right = new Queue<object>();
        //Dequeue() and Count() have a time complexity of O(1)

        if (input.Count <= 1)
            return input;

        int midpoint = input.Count / 2;

        for (int i = 0; i < midpoint; i++)
            Left.Enqueue(input[i]);
        for (int i = midpoint; i < input.Count; i++)
            Right.Enqueue(input[i]);

        Left = new Queue<object>(Sort(Left.ToList(), comparison)); //Recursion! :o
        Right = new Queue<object>(Sort(Right.ToList(), comparison)); ; //This line and the one above split the list into smaller lists (left and right)

        Result = Merge(Left, Right, comparison); //This joins the lists together

        return Result;
    }

    private static List<object> Merge(Queue<object> Left, Queue<object> Right, Comparison<object> comparison)
    {
        int cmp = comparison(Left.Peek(), Right.Peek());
        //If cmp is less than 0, left is less. If it is greater, left is greater

        List<object> Result = new List<object>();
        while (Left.Count /* O(1) operation */ > 0 && Right.Count > 0)
        {
            if (cmp < 0)
                Result.Add(Left.Dequeue());
            //Left.RemoveAt(0) - Using a list to remove at a certain point is inefficient
            else
                Result.Add(Right.Dequeue());
        }

        while (Left.Count > 0)
            Result.Add(Left.Dequeue());

        while (Right.Count > 0)
            Result.Add(Right.Dequeue());

        return Result;
    }
}
}

Использование:

Entities = MergeSort.Sort(Entities, (p, q) => p.F.CompareTo(q.F)).ToList();

person Shivam Malhotra    schedule 01.09.2013    source источник


Ответы (1)


Обычно лучшая подпись похожа на ту, которую использует List<T>.Sort(...):

static void MergeSort<T>(IList<T> coll, Comparison<T> comparison)
{
    ...
    // < 0 coll[i] < coll[j], == 0 coll[i] == coll[j], > 0 coll[i] > coll[j]
    int cmp = comparison(coll[i], coll[j]);
    ...
}

использовать:

MergeSort(coll, (p, q) => p.F.CompareTo(q.F));

Обратите внимание, что если F является целым числом, часто вы будете видеть такие сравнения, как: (p, q) => p.F - q.F. Это работает, потому что если p.F > q.F, то p.F - q.F > 0 и так далее.

Другой возможный вариант — тот, который используется LINQ OrderBy(...).

Обычно лучшая подпись похожа на ту, которую использует List<T>.Sort(...):

static void MergeSort<T, TKey>(IList<T> coll, Func<T, TKey> selector)
{
    var comparer = Comparer<Tkey>.Default;

    ...
    // < 0 coll[i] < coll[j], == 0 coll[i] == coll[j], > 0 coll[i] > coll[j]
    int cmp = comparer(selector(coll[i]), selector(coll[j]));
    ...
}

использовать:

MergeSort(coll, p => p.F);

Здесь мы передаем методу делегат, способный вернуть «ключ сортировки», например p => p.F. Это немного медленнее и сложнее в использовании (но, вероятно, используется в LINQ, потому что больше похоже на то, что делается в SQL)

person xanatos    schedule 01.09.2013
comment
Ах! страшные вещи ... Я прочитаю это несколько раз, возьму и посмотрю, понимаю ли я, что вы говорите: P - person Shivam Malhotra; 01.09.2013
comment
Боюсь, ты потерял меня. Что хранит int cmp? Удерживает ли он разницу? - person Shivam Malhotra; 01.09.2013
comment
Теперь все понятно :D Большое спасибо! Я выбрал метод List.sort - person Shivam Malhotra; 01.09.2013
comment
@ShivamMalhotra Это сравнение. Это ‹ 0, если coll1[i] ‹ coll2[j], == 0, если coll1[i] == coll2[j] и т. д. - person xanatos; 01.09.2013
comment
MergeSort(coll1, coll2, (p, q) => p.F.CompareTo(q.F)); выдает мне ошибку. Имеет недопустимые аргументы - person Shivam Malhotra; 01.09.2013
comment
@ShivamMalhotra Какие бывают типы coll1, coll2, F? - person xanatos; 01.09.2013
comment
Я думаю, будет лучше, если вы увидите мой код? coll1 и 2 — это Entities, заданные для параметра Object, а F — целое число. Как я могу показать вам мой код? Я внесу правки в свой вопрос - готово. - person Shivam Malhotra; 01.09.2013
comment
@ShivamMalhotra Начните с изменения всего объекта на T и создания методов Sort<T> и Merge<T> - person xanatos; 01.09.2013
comment
Но что такое Т в этом случае? Его не существует? Должен сейчас! - person Shivam Malhotra; 01.09.2013
comment
@ShivamMalhotra Это называется общий параметр. Он существует только при вызове метода. - person xanatos; 01.09.2013
comment
Все сделано. Но снова получил другую ошибку в том же заявлении. p.F и q.F - в нем говорится, что определение не содержится - person Shivam Malhotra; 01.09.2013
comment
давайте продолжим это обсуждение в чате - person Shivam Malhotra; 01.09.2013