Детерминированный вид списка объектов - PullRequest
0 голосов
/ 31 августа 2018

Мне нужно отсортировать список объектов и произвольное свойство сортировки. Если в моем списке несколько объектов, имеющих одно и то же значение для этого свойства сортировки, то многократная сортировка одного и того же списка приведет к перестановке членов с одним и тем же значением свойства сортировки. Чтобы было ясно, каждый раз, когда сортировка выполняется, генерируется новый список, и порядок элементов является произвольным и не обязательно совпадает с тем, который был в последний раз, когда список был отсортирован. Есть ли способ избежать этого?

Вот пример кода:

List<T> myList; // T is arbitrary and I doesn't implement any common interface
PropertyInfo sortPorperty = some property of T

var sortedList = myList.OrderBy(x => sortProperty.GetValue(x));

Многократное выполнение этого кода приведет к разному порядку объектов.

Моя первоначальная идея - также сортировать по самому объекту

var sortedList = myList.OrderBy(x => sortProperty.GetValue(x)).ThenBy(x => x);

Но, насколько я могу судить, он будет сортироваться по хеш-коду, и это в основном место в памяти объекта, поэтому между запусками оно будет другим. Есть ли что-нибудь еще, что будет работать?

1 Ответ

0 голосов
/ 31 августа 2018

Если тип сериализуем, то вы можете использовать сериализацию объекта, чтобы служить окончательным критерием сортировки.

Используйте BinaryFormatter, чтобы сгенерировать уникальную строку для объекта (которую я назвал Idem в этом примере) и использовать ее в качестве окончательного .ThenBy критерия сортировки.

В этом примере я преобразовал бинарно-отформатированную версию объекта в строку base64 (это наверняка накладные расходы производительности, и есть другие подходы, чтобы сделать бинарные версии более подходящими для сравнения, но я просто иллюстрирую общий подход). .)

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

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;

public static class Extensions
{
    // Returns a string unique(TM) to this object.
    public static string Idem<T>(this T toSerialize)
    {
        BinaryFormatter formatter = new BinaryFormatter();
        var memoryStream = new MemoryStream();
        using (memoryStream)
        {
            formatter.Serialize(memoryStream, toSerialize);
            return Convert.ToBase64String(memoryStream.ToArray());
        }
    }
}

[Serializable()]
public class Person
{
    public Person(string name, string secret)
    {
        this.name = name;
        this.secret = secret;
    }

    private string secret; // some private info
    public string Nickname { get { return name; } } // some property
    public string name; // some public info

    public override string ToString() // a way to see the private info for this demo
    {
        return string.Format("{0} ({1})", name, secret);
    }
}

class Program
{
    static void Main(string[] args)
    {
        // You can rearrange the items in this list and they will always come out in the same order.
        List<Person> myList = new List<Person>() {
            new Person("Bob", "alpha"),
            new Person("Bob", "bravo"),
            new Person("Alice", "delta"),
            new Person("Bob", "echo"),
            new Person("Bob", "golf"),
            new Person("Bob", "foxtrot"),
        };
        PropertyInfo sortProperty = typeof(Person).GetProperty("Nickname");

        Random random = new Random();
        for (int i = 0; i < 3; ++i)
        {
            var randomList = myList.OrderBy(x => random.Next());


            var sortedList = randomList.OrderBy(x => sortProperty.GetValue(x))
                .ThenBy(x => x.Idem()); // Here's the magic "Then By Idem" clause.

            Console.WriteLine(string.Join(Environment.NewLine, sortedList));
            Console.WriteLine();
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...