我对排序集合感兴趣,但也返回一个索引,可用于映射到集合中的原始位置(排序之前)。
让我举一个例子来说明一点:
List<int> A = new List<int>(){3,2,1};
List<int> B;
List<int> idx;
Sort(A,out B,out idx);
之后:
A = [3,2,1]
B = [1,2,3]
idx = [2,1,0]
所以A,B,idx之间的关系是:
A[i] == B[ idx[i] ]
,i = 0 ... 2
C#/ .Net是否有任何内置机制使其易于实现?
感谢。
答案 0 :(得分:47)
使用Linq可以很容易地完成。
以下是一些用于演示原理的代码:
List<int> A = new List<int>() { 3, 2, 1 };
var sorted = A
.Select((x, i) => new KeyValuePair<int, int>(x, i))
.OrderBy(x => x.Key)
.ToList();
List<int> B = sorted.Select(x => x.Key).ToList();
List<int> idx = sorted.Select(x => x.Value).ToList();
我认为这给了A [idx [i]] = B [i],但希望这对你来说已经足够了。
答案 1 :(得分:18)
虽然Mark Byers使用LINQ为您提供了solution,但我想向您展示使用.NET Framework的另一种解决方案。
Array.Sort
会超载,会为您执行此操作:
int[] a = new[] { 3, 2, 1 };
int[] p = new[] { 0, 1, 2 };
Array.Sort(a, p);
Assert.IsTrue(a.SequenceEquals(new[] { 1, 2, 3 }));
Assert.IsTrue(p.SequenceEquals(new[] { 2, 1, 0 }));
因此,这是一个符合您的规范的通用方法,可以利用这种重载:
void Sort<T>(
List<T> input,
out List<T> output,
out List<int> permutation,
IComparer<T> comparer
) {
if(input == null) { throw new ArgumentNullException("input"); }
if(input.Count == 0) {
// give back empty lists
output = new List<T>();
permutation = new List<int>();
return;
}
if(comparer == null) { throw new ArgumentNullException("comparer"); }
int[] items = Enumerable.Range(0, input.Count).ToArray();
T[] keys = input.ToArray();
Array.Sort(keys, items, comparer);
output = keys.ToList();
permutation = items.ToList();
}
答案 2 :(得分:5)
使用lambda以某种方式更优雅的方法
Array.Sort<int>(idx, (a, b) => A[a].CompareTo(A[b]));
这给出了来自A数组的idx数组
答案 3 :(得分:1)
就目前而言,您也可以使用匿名类型或值元组代替KeyValuePair
。它将提供更精确的命名,并使您的代码更具可读性:
匿名类型(C#3.0):
List<int> arr = new List<int>() { 3, 2, 1 };
var sorted = arr
.Select((x, i) => new { Value = x, OriginalIndex = i }))
.OrderBy(x => x.Value)
.ToList();
int originalIndexOfTheSmallestItem = sorted[0].OriginalIndex;
List<int> B = sorted.Select(x => x.Value).ToList();
List<int> idx = sorted.Select(x => x.OriginalIndex).ToList();
值元组(C#7.0):
List<int> arr = new List<int>() { 3, 2, 1 };
var sorted = arr
.Select((x, i) => (Value: x, OriginalIndex: i))
.OrderBy(x => x.Value)
.ToList();
int originalIndexOfTheSmallestItem = sorted[0].OriginalIndex;
List<int> B = sorted.Select(x => x.Value).ToList();
List<int> idx = sorted.Select(x => x.OriginalIndex).ToList();
区别在于您可以从方法中返回值元组并使用它,但是匿名类型只能在此方法中使用。