Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Sort list while also returning the original index positions?

I'm interested in sorting a collection, but also returning an index which can be used to map to the original position in the collection (before the sort).

Let me give an example to be more clear:

List<int> A = new List<int>(){3,2,1};
List<int> B;
List<int> idx;

Sort(A,out B,out idx);

After which:

A = [3,2,1] 
B = [1,2,3]
idx = [2,1,0]

So that the relationship between A,B,idx is:

A[i] == B[ idx[i] ] , for i = 0...2

Does C#/.Net have any built in mechanism to make this easy to implement?

Thanks.

like image 525
homie347 Avatar asked Nov 19 '09 00:11

homie347


People also ask

What do you mean by C?

" " C is a computer programming language. That means that you can use C to create lists of instructions for a computer to follow. C is one of thousands of programming languages currently in use.

What is the full name of C?

In the real sense it has no meaning or full form. It was developed by Dennis Ritchie and Ken Thompson at AT&T bell Lab. First, they used to call it as B language then later they made some improvement into it and renamed it as C and its superscript as C++ which was invented by Dr.

What is C in coding language?

C is a powerful general-purpose programming language. It can be used to develop software like operating systems, databases, compilers, and so on. C programming is an excellent language to learn to program for beginners. Our C tutorials will guide you to learn C programming one step at a time.

Is C programming hard?

C is more difficult to learn than JavaScript, but it's a valuable skill to have because most programming languages are actually implemented in C. This is because C is a “machine-level” language. So learning it will teach you how a computer works and will actually make learning new languages in the future easier.


4 Answers

It can be done quite easily using Linq.

  • Convert your list into a new list of pairs (object, original index of object).
  • Sort the new list by the first item in the pair
  • Extract the sorted list and the original indices.

Here's some code to demonstrate the principle:

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

I think this gives A[idx[i]] = B[i], but that hopefully is good enough for you.

like image 136
Mark Byers Avatar answered Oct 14 '22 07:10

Mark Byers


While Mark Byers provided you a solution using LINQ, I want to show you another solution using the .NET Framework.

There is an overload of Array.Sort that will do this for you:

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

Thus, here is a generic method meeting your specification that leverages this overload:

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();   
}
like image 21
jason Avatar answered Oct 14 '22 06:10

jason


a somehow more elegant approach using lambda

Array.Sort<int>(idx, (a, b) => A[a].CompareTo(A[b]));

this gives u idx array from the A array

like image 8
Mohamed BenHaddou Avatar answered Oct 14 '22 07:10

Mohamed BenHaddou


As for now, you can also utilize anonymous types or value tuples instead of KeyValuePair. It will provide more precise naming and make your code more readable:

Anonymous types (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();

Value tuples (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();   

The difference is that you can return value tuple from your method and use it, but anonymous type can only be used within this method.

like image 1
Yeldar Kurmangaliyev Avatar answered Oct 14 '22 05:10

Yeldar Kurmangaliyev