Deterministic sort of a list of objects

早过忘川 提交于 2021-01-29 05:27:55

问题


I need to sort a list of objects and an arbitrary sort property. If there are multiple objects in my list that have the same value for that sort property, then repeatedly sorting the same list will rearrange the members with the same value of sort property. To be clear, each time sort is run, a new list is generated and the order of members is arbitrary and not necessarily the same as it was the last time the list was sorted. Is there a way to avoid this?

Here is a code sample:

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));

Multiple executions of this code will result in different order of the objects.

My initial idea is to also sort by the object itself

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

But as far as I can tell that will sort by hashcode and that is basically the memory location of an object so it would not be the same between runs. Is there anything else that would work?


回答1:


If the type is serializable then you can use the serialization of the object to serve as the final sort criteria.

Use BinaryFormatter to generate a unique string for the object (which I have called Idem in this example) and use that as the final .ThenBy sorting criteria.

In this example I transformed the binary formatted version of the object to a base64 string (that's performance overhead for sure, and there are other approaches to get the the binary versions to compare nicely, but I'm just illustrating the general approach.)

I think this example has everything you asked for. Arbitrary type with no interface, uses a property as the OrderBy criteria, and does not rely on the initial order of the items to produce the same order of the output on subsequent runs.

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();
        }
    }
}


来源:https://stackoverflow.com/questions/52119625/deterministic-sort-of-a-list-of-objects

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!