2010-01-19 23 views
7

¿Es posible mejorar la eficiencia de esas solicitudes linq? Uso dos bucles diferentes ... ¿Me pueden ayudar a optimizar este código?¿Linq en 2 matrices en 1 bucle?

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

Este código de Python es como que si lo prefiere:

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

se dará cuenta que, en este código Python, yo uso una sola especie. ese no es el caso de este código C#.

deberíamos obtener al final:

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

Fred

Editar: uso el programa de Diadistis (después de una pequeña corrección)

Así que aquí vamos: Array.Sort (x, y) (0.05) es la manera más rápida de seguir (0.18) por

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

Las otras soluciones son bastante equivalentes (~ 0,35) en el consumo de tiempo en mi pc.

Si alguien tiene una idea interesante, la perfilaré y actualizaré esta publicación.

+0

No, eso se ve bien para mí. ¿Quizás quiso decir 'orderby y [n]' en la primera declaración? – leppie

+1

no, eso fue intencional. – Frederic

+0

¿Qué hace tu código? – dtb

Respuesta

12

Está bien, pero yo preferiría una sintaxis más simple:

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

double[] x_sorted = x.OrderBy(d => d).ToArray(); 
double[] y_sorted = y.OrderBy(d => d).ToArray(); 

Editar:

Argh ... no pude detectar que se trataba de una asociativo tipo de matriz.

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

double[] y_sorted = y.Clone() as double[]; 
double[] x_sorted = x.Clone() as double[]; 

Array.Sort(x_sorted, y_sorted); 

Editar 2 1/2

y algunas pruebas de rendimiento:

public class Program 
{ 
    delegate void SortMethod(double[] x, double[] y); 

    private const int ARRAY_SIZE = 3000000; 

    private static Random RandomNumberGenerator = new Random(); 

    private static double[] x = GenerateTestData(ARRAY_SIZE); 
    private static double[] y = GenerateTestData(ARRAY_SIZE); 

    private static double[] GenerateTestData(int count) 
    { 
     var data = new double[count]; 

     for (var i = 0; i < count; i++) 
     { 
      data[i] = RandomNumberGenerator.NextDouble(); 
     } 

     return data; 
    } 

    private static void SortMethod1(double[] x, double[] y) 
    { 
     Array.Sort(x, y); 
    } 

    private static void SortMethod2(double[] x, double[] y) 
    { 
     IEnumerable<int> range = Enumerable.Range(0, x.Length); 
     x = (from n in range orderby x[n] select y[n]).ToArray(); 
     y = (from n in range orderby x[n] select x[n]).ToArray(); 
    } 

    private static void SortMethod3(double[] x, double[] y) 
    { 
     int[] x_index = 
      Enumerable.Range(0, x.Length).OrderBy(i => x[i]).ToArray(); 

     x = x_index.Select(i => x[i]).ToArray(); 
     y = x_index.Select(i => y[i]).ToArray(); 
    } 

    private static void SortMethod4(double[] x, double[] y) 
    { 
     int[] range = 
      Enumerable.Range(0, x.Length).OrderBy(i => x[i]).ToArray(); 

     var q = (
      from n in range 
      orderby x[n] 
      select new { First = x[n], Second = y[n] }).ToArray(); 

     x = q.Select(t => t.First).ToArray(); 
     y = q.Select(t => t.Second).ToArray(); 
    } 

    private static void SortMethodPerformanceTest(SortMethod sortMethod) 
    { 
     double[] y_sorted = y.Clone() as double[]; 
     double[] x_sorted = x.Clone() as double[]; 

     var sw = new Stopwatch(); 

     sw.Start(); 
     sortMethod.Invoke(x_sorted, y_sorted); 
     sw.Stop(); 

     Console.WriteLine(
      string.Format(
       "{0} : {1}", 
       sortMethod.Method.Name, 
       sw.Elapsed)); 
    } 

    static void Main(string[] args) 
    { 
     Console.WriteLine("For array length : " + ARRAY_SIZE); 
     Console.WriteLine("------------------------------"); 

     SortMethodPerformanceTest(SortMethod1); 
     SortMethodPerformanceTest(SortMethod2); 
     SortMethodPerformanceTest(SortMethod3); 
     SortMethodPerformanceTest(SortMethod4); 

     Console.WriteLine("Press any key to continue..."); 
     Console.ReadKey(); 
    } 
} 

y los resultados:

 
For array length : 3000000 
------------------------------ 
SortMethod1 : 00:00:00.6088503 // Array.Sort(Array, Array) 
SortMethod2 : 00:00:07.9583779 // Original 
SortMethod3 : 00:00:04.5023336 // dtb's Linq Alternative 
SortMethod4 : 00:00:06.6115911 // Christian's Linq Alternative 
+0

También evite llamar a 'ToArray()' a menos que realmente lo requiera - usted obtiene un 'IEnumerable ' que aplaza la ejecución hasta que sea necesario. – GraemeF

+3

+1 para Array.Sort (Array, Array) – dtb

+0

hay un error en su programa. siempre llama a SortMethod1 ... – Frederic

2

También se puede hacer después. Teniendo en cuenta que si nos referimos y [n] como en el comentario leppie

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

actualización

debe ser tan siguiente para obtener el resultado correcto.

double[] x = { 2, 3, 1, 5, 7, 2, 3 }; 
    double[] y = { 1, 2, 3, 4, 5, 6, 7 }; 
    Array.Sort<double, double>(x, y); 
+0

Este código no crea nuevas matrices. Se ordena en su lugar. – affan

+0

+1; clonar la matriz si el original debe mantenerse intacto. –

4

Si leo el código correctamente, está intentando ordenar dos matrices por los elementos de la primera matriz.

La traducción literal de su código Python a C# sería algo como esto:

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

Como alternativa, puede comprimir las dos matrices a un enumerable de tuplas y luego resolver esto por el primer elemento:

var sorted = Enumerable.Zip(x, y, Tuple.Create<double, double>) 
         .OrderBy(t => t.Item1) 
         .ToArray(); 
+0

aie. Olvidé una restricción ... Uso .net3.5 (¡pero realmente preferiría usar .net4!) – Frederic

+0

Puede definir fácilmente un método Zip y Tuples en .NET3.5 usted mismo. – dtb

+0

ok, digamos que las funciones de .net 4 son admitidas :) – Frederic

2

Esto podría ser más rápido, ya que sólo una especie vez:

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

Nice; similar a mi respuesta Tuple. Necesita agregar un ToArray para evitar q se ejecute dos veces. – dtb

+0

@dtb: Gracias, incorporó su mejora. – Christian

+0

No hay idea si esto es una mejora en términos de velocidad. Solo señalé que q se ejecutó dos veces, lo que pensé que podría no ser lo que pretendías. – dtb