如何让C# SortedList的嵌套字符串按键实现数值排序?
Great observation on how SortedList handles different key types! The issue you're facing with semicolon-separated string keys (like "0;0", "0;10") is that the default string comparer uses lexicographical order, which doesn't align with numerical sorting for your composite keys. Let's break down how to fix this, leveraging the work you've already done with your Plates class.
Core Idea
We need to compare these string keys by first splitting them into integer arrays, then comparing the arrays numerically (element by element). Since you already have a Comparer<int[]> implementation in your Plates class, we can reuse that logic to build a custom string key comparer for SortedList.
Step 1: Ensure Your int[] Comparer is Fully Implemented
First, make sure your Plates class's Compare method correctly handles numerical sorting of integer arrays. Here's a robust example if you haven't finalized it:
public class Plates : Comparer<int[]>, IEnumerable<KeyValuePair<string, Plate>> { // Implement the integer array comparison logic public override int Compare(int[] x, int[] y) { if (x == null && y == null) return 0; if (x == null) return -1; if (y == null) return 1; // Compare elements one by one until a difference is found int minLength = Math.Min(x.Length, y.Length); for (int i = 0; i < minLength; i++) { int elementComparison = x[i].CompareTo(y[i]); if (elementComparison != 0) return elementComparison; } // If all compared elements are equal, shorter array comes first return x.Length.CompareTo(y.Length); } // Rest of your Plates class implementation (IEnumerable, etc.) goes here }
Step 2: Build a Custom String Key Comparer
Create an IComparer<string> that converts your semicolon-separated keys to int[] and uses your existing array comparer to determine order:
public class SemicolonKeyComparer : IComparer<string> { private readonly Comparer<int[]> _arrayComparer; // Use your Plates class's array comparison logic public SemicolonKeyComparer(Plates platesComparer) { _arrayComparer = platesComparer ?? new Plates(); } public int Compare(string x, string y) { if (string.IsNullOrEmpty(x) && string.IsNullOrEmpty(y)) return 0; if (string.IsNullOrEmpty(x)) return -1; if (string.IsNullOrEmpty(y)) return 1; // Split strings into integer arrays int[] xArray = x.Split(';').Select(int.Parse).ToArray(); int[] yArray = y.Split(';').Select(int.Parse).ToArray(); // Reuse the array comparison logic from Plates return _arrayComparer.Compare(xArray, yArray); } }
Step 3: Integrate the Comparer with Your SortedList
Update your Plates class to use this custom comparer when initializing its internal SortedList (assuming you're using a SortedList as the backing store):
public class Plates : Comparer<int[]>, IEnumerable<KeyValuePair<string, Plate>> { private readonly SortedList<string, Plate> _internalSortedList; public Plates() { // Initialize the SortedList with our custom key comparer _internalSortedList = new SortedList<string, Plate>(new SemicolonKeyComparer(this)); } // Add method to insert new plates public void Add(string key, Plate plate) { _internalSortedList.Add(key, plate); } // Implement IEnumerable to expose sorted key-value pairs public IEnumerator<KeyValuePair<string, Plate>> GetEnumerator() { return _internalSortedList.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } // Your existing Compare method from Step 1 goes here }
Testing the Solution
When you use the Plates class now, your keys will sort numerically instead of lexicographically:
var plates = new Plates(); plates.Add("0;10", new Plate()); plates.Add("0;2", new Plate()); plates.Add("1;0", new Plate()); // Iterating over plates will return keys in this order: "0;2", "0;10", "1;0"
Notes
- Add error handling if your keys might contain non-numeric values (e.g., wrap
int.Parsein atry-catchblock or useint.TryParse). - This approach works for any number of semicolon-separated segments (e.g., "1;2;3" will sort correctly against "1;2;10").
内容的提问来源于stack exchange,提问作者PetrasVestartasEPFL

