tags:

views:

279

answers:

4

Hi,

Is it possible to improve the efficiency of those linq requests? I use two different loops... Can you help me to optimize this code?

        double[] x = { 2, 3, 1, 5, 7, 2, 3 };
        double[] y = { 1, 2, 3, 4, 5, 6, 7 };            
        IEnumerable<int> range = Enumerable.Range(0, x.Length);
        double[] y_sorted = (from n in range orderby x[n] select y[n]).ToArray();
        double[] x_sorted = (from n in range orderby x[n] select x[n]).ToArray();

This code in python is like that if you prefer:

        x_index = argsort(x)
        x_sorted = [x[i] for i in x_index]
        y_sorted = [y[i] for i in x_index]

you will notice that, in this python code, i use only one sort. that's not the case of this c# code.

we should get at the end:

        x_sorted = { 1, 2, 2, 3, 3, 5, 7 }
        y_sorted = { 3, 1, 6, 2, 7, 4, 5 }

Fred

Edit: I use the program of Diadistis (after a small correction)

So here we go: Array.Sort(x, y) (0.05) is the fastest way following (0.18) by

        int[] x_index = Enumerable.Range(0, x.Length).OrderBy(i => x[i]).ToArray();
        double[] x_sorted = x_index.Select(i => x[i]).ToArray();
        double[] y_sorted = x_index.Select(i => y[i]).ToArray();

The other solutions are quite equivalent (~0.35) in time consumption on my pc.

If someone have an interesting idea, I will profile it and update this post.

+10  A: 
Diadistis
Also avoid calling `ToArray()` unless really required - you get an `IEnumerable<double>` which defers execution until necessary.
GraemeF
+1 for Array.Sort(Array,Array)
dtb
there is a mistake in your program. you always call SortMethod1...
Frederic
o_O indeed, not my day....
Diadistis
After fixing this the results now make sense
Diadistis
+2  A: 

You can also do following. Keeping in view that if you meant y[n] as in leppie comment

double[] x = { 2, 3, 1, 5, 7, 2, 3 };        
double[] y = { 2, 3, 1, 5, 7, 2, 3 };  

Array.Sort<double>(x);
Array.Sort<double>(y);

Update

Should be as following to get correct result.

    double[] x = { 2, 3, 1, 5, 7, 2, 3 };
    double[] y = { 1, 2, 3, 4, 5, 6, 7 }; 
    Array.Sort<double, double>(x, y);
affan
This code does not create new arrays. It sort in place.
affan
+1; clone the array if the original should be kept intact.
Anton Tykhyy
+4  A: 

If I read your code correctly, you're trying to sort two arrays by the elements of the first array.

The literal translation of your Python code to C# would be something like this:

int[] x_index = Enumerable.Range(0, x.Length).OrderBy(i => x[i]).ToArray();
double[] x_sorted = x_index.Select(i => x[i]).ToArray();
double[] y_sorted = x_index.Select(i => y[i]).ToArray();

Alternatively, you could zip the two arrays to an enumerable of tuples and then sort this by the first item:

var sorted = Enumerable.Zip(x, y, Tuple.Create<double, double>)
                       .OrderBy(t => t.Item1)
                       .ToArray();
dtb
aie. I forgot one constraint... I use .net3.5 (but I really would prefer to use .net4!!)
Frederic
You can easily define a Zip method and Tuples in .NET3.5 yourself.
dtb
ok let's say functions from .net 4 are admitted :)
Frederic
+2  A: 

This could be faster as you only sort once:

var q =
    (from n in range
    orderby x[n]
    select new { First = x[n], Second = y[n] }).ToArray();
double[] x_sorted = q.Select(t => t.First).ToArray();
double[] y_sorted = q.Select(t => t.Second).ToArray();
Christian
Nice; similar to my Tuple answer. You need to add a ToArray to prevent q from being executed twice.
dtb
@dtb: Thanks, incorporated your improvement.
Christian
No idea if this is an improvement in terms of speed. I just pointed out that q was executed twice which I thought may not be what you intended.
dtb