Tengo un csv cadena que contiene dobles (e.g», 0.3,0.4,0.3″), y quiero ser capaz de emitir una matriz de tipo double que contiene la suma acumulativa de estos números (e.g [0.3,0.7,1.0]).

Hasta el momento, he

double[] probabilities = textBox_f.Text.Split(new char[]{','}).Select(s => double.Parse(s)).ToArray();

que da los números como una matriz, pero no la suma total de los números.

Es allí cualquier manera de continuar esta expresión para obtener lo que quiero, o tengo que utilizar la iteración para crear una nueva matriz a partir de la matriz de la que ya tengo?

Me gusta aprender nuevas tecnologías y formas de hacer las cosas. Es perfectamente posible que otras formas son mejores o más rápido, pero esto es algo que no sé cómo hacer, y le gustaría así
Y ¿por qué? Si una solución sin LINQ es tanto más rápido de tipo y más rápido para ejecutar, ¿por qué debería estar interesado en el LINQ solución? Y por qué LINQ específicamente, de todos modos — ¿por qué no preguntar acerca de una solución que utiliza los medicamentos genéricos, o dynamic, o cualquier otra característica al azar que no es necesario responder a la pregunta?
Split(new char[]{','}) , equivalentemente, puede ser escrito Split(',') ya que el parámetro se declara con params.
La vieja pregunta, pero tengo que comentar. La pregunta es acerca de cómo hacer esto en LINQ, no es la forma de hacerlo sin LINQ.
La felicito por la pregunta pero me debe preguntarse por qué seleccionó la respuesta por Blindy que (actualmente) ha -3 puntos? Definitivamente no es una buena respuesta. Personalmente me ha gustado Eric Lippert o Andrey respuestas mejor. Sólo me preguntaba su opinión sobre esta cuestión casi 5 años más tarde.

OriginalEl autor simonalexander2005 | 2011-01-28

9 Comentarios

  1. 0
    var input=new double[]{ ... }
    double sum=0;
    
    var output=input
        .Select(w=>sum+=w);
    El uso de las consultas de LINQ sólo por sus efectos secundarios es una mala idea para un número de razones, no menos importante de los cuales es el hecho de que los futuros lectores de el código no espera que esta … viola el principio de la menor sorpresa.
    Wow, muy corto… y muy chapucero. Por favor, no me pregunte a mantener tu código!
    Este es un muy, muy mala idea. LBushkin que es correcto. por Favor, no escribir consultas que tienen efectos secundarios. Las consultas deben consulta de datos, no modificar.
    Puede usted explicar cómo Seleccionar difiere de mapa? (Y cómo es la mutación de una variable como un efecto secundario de una comprensión de la consulta «funcional»?)
    y yo esperaría un Haskell programador para ser totalmente horrorizado por lo que has hecho. Haskell es todo acerca de cómo evitar los efectos secundarios y las mutaciones como este.

    OriginalEl autor Blindy

  2. 45

    Hay un tiempo para la generalidad, y hay un tiempo para resolver el problema planteado. Este es uno de los último tiempos. Si usted desea hacer un método que convierte una secuencia de dobles en una secuencia de sumas parciales, a continuación, sólo hacer que:

    public static IEnumerable<double> CumulativeSum(this IEnumerable<double> sequence)
    {
        double sum = 0;
        foreach(var item in sequence)
        {
            sum += item;
            yield return sum;
        }        
    }

    Fácil. No liarte con los agregados y las consultas complicadas y otras cosas. Fácil de entender, fácil de depurar, fácil de usar:

    textBox_f.Text
        .Split(new char[]{','})
        .Select(s => double.Parse(s))
        .CumulativeSum()
        .ToArray();

    Ahora, debo señalar que si que es la entrada del usuario, a continuación, haga doble.Parse puede lanzar una excepción, ya que podría ser una mejor idea para hacer algo como:

    public static double? MyParseDouble(this string s)
    {
        double d;
        if (double.TryParse(s, out d))
            return d;
        return null;
    }
    
    public static IEnumerable<double?> CumulativeSum(this IEnumerable<double?> sequence)
    {
        double? sum = 0;
        foreach(var item in sequence)
        {
            sum += item;
            yield return sum;
        }        
    }
    ...
    textBox_f.Text
        .Split(new char[]{','})
        .Select(s => s.MyParseDouble())
        .CumulativeSum()
        .ToArray();

    y ahora usted no consigue una excepción si el usuario comete un error de escritura, se puede obtener valores nulos.

    OriginalEl autor Eric Lippert

  3. 19

    Tuve un requisito similar hace algún tiempo. Básicamente, necesitaba hacer una agregación, pero también necesitaba para seleccionar cada valor intermedio. Así que escribí un método de extensión denominado SelectAggregate (probablemente no es el nombre más adecuado, pero no pude encontrar algo mejor) que puede ser utilizada como que:

    double[] numbers = new [] { 0.3, 0.4, 0.3 };
    double[] cumulativeSums = numbers.SelectAggregate(0.0, (acc, x) => acc + x).ToArray();

    Aquí está el código :

        public static IEnumerable<TAccumulate> SelectAggregate<TSource, TAccumulate>(
            this IEnumerable<TSource> source,
            TAccumulate seed,
            Func<TAccumulate, TSource, TAccumulate> func)
        {
            source.CheckArgumentNull("source");
            func.CheckArgumentNull("func");
            return source.SelectAggregateIterator(seed, func);
        }
    
        private static IEnumerable<TAccumulate> SelectAggregateIterator<TSource, TAccumulate>(
            this IEnumerable<TSource> source,
            TAccumulate seed,
            Func<TAccumulate, TSource, TAccumulate> func)
        {
            TAccumulate previous = seed;
            foreach (var item in source)
            {
                TAccumulate result = func(previous, item);
                previous = result;
                yield return result;
            }
        }
    +1 — una buena solución que también enseña cómo escribir código reutilizable!

    OriginalEl autor Thomas Levesque

  4. 5

    Desea utilizar el Aggregate operador, con un List<double> como la agregación de acumulador. De esa manera se puede producir una proyección de lo que es en sí mismo una secuencia de sumas.

    He aquí un ejemplo para empezar:

    double[] runningTotal = textBox_f.Text
                .Split(new char[]{','})
                .Select(s => double.Parse(s))
                .Aggregate((IEnumerable<double>)new List<double>(), 
                           (a,i) => a.Concat(new[]{a.LastOrDefault() + i}))
                .ToArray();
    esto es ineficiente, se calculará la Suma en cada momento lo que es O(n^2)
    No se compila. Por favor, probar el código antes de publicar 🙁
    Gran respuesta, y me puso mirando agregados – pero al final opté por el otro. Gracias
    Mi original de la aplicación incorrecta, en realidad. Me refería a usar LastOrDefault() … ya que el último elemento en el total de ejecución es ya la suma acumulada de todos los elementos anteriores a él. La única inneficiency restante es la creación de intermedio secuencias … que para la mayoría de los casos de uso deben ser mínimos. La aplicación ahora compila y genera el resultado esperado.

    OriginalEl autor LBushkin

  5. 2

    ¿Por qué necesita para ser LINQ?

    var cumulative = new double[probabilities.Length];
    for (int i = 0; i < probabilities.Length; i++)
        cumulative[i] = probabilities[i] + (i == 0 ? 0 : cumulative[i-1]);
    Quizás por la misma razón por la que ha de ser la suma acumulativa, una matriz de números y C#?

    OriginalEl autor Timwi

  6. 2

    Primero que todo no creo que es una buena tarea para Linq. El viejo y simple foreach lo hará mejor. Pero como un rompecabezas que está bien.

    Primera idea fue utilizar subconsultas, pero no me gusta, porque es de O(n^2). Aquí está mi lineal solución:

            double[] probabilities = new double[] { 0.3, 0.4, 0.3};
            probabilities
                .Aggregate(
                    new {sum=Enumerable.Empty<double>(), last = 0.0d},
                    (a, c) => new {
                        sum = a.sum.Concat(Enumerable.Repeat(a.last+c,1)),
                        last = a.last + c
                    },
                    a => a.sum
                );
    Sé que es siete años más tarde, pero no llegué a ver esta solución hasta ahora. Aunque esta solución es lineal en el tiempo, también es lineal en su uso de espacio de pila, y eso es realmente malo, un relativamente pequeño de la matriz de entrada hará que la pila de desbordamiento. ¿Ves porque es lineal en el espacio de la pila? Sugerencia: el desbordamiento está en el código que no escribir. Escribir ese código y a ver qué pasa!
    que es un interesante comentario. No estoy seguro de lo que podría causar lineal de la pila de asignación de espacio. ¿Concat Efectiva de los rendimientos de la secuencia de almacenar en la pila? github.com/Microsoft/referencesource/blob/master/System.Core/…
    Aquí un poco del programa. Antes de ejecutarlo, tratar de predecir lo que el resultado va a ser. A continuación, tratar; fueron sorprendidos? dotnetfiddle.net/9akiA5 ahora debería estar claro que la pila se consume.
    sí, parece que mi suposición era correcta, ConcatIterator usa la pila para recorrer la lista. Gracias por señalarlo a él, yo no tenía ni idea de que es imprudente uso Concat para listas largas.
    Solo para aclarar su comentario: el problema es cuando se tiene un gran número de concatenaciones. La concatenación de dos de las secuencias está bien. El problema surge cuando se concatenar un elemento en una secuencia, y luego concatenar un elemento en la secuencia, y luego concatenar un elemento en la secuencia, y luego concatenar un elemento en la secuencia, … y a ver cómo va. Podemos construir una cadena de objetos en el heap que cuando iterado cada uno de los desencadenantes de una llamada de método, y el va a la pila.

    OriginalEl autor Andrey

  7. 1

    el uso de RX :

    var input=new double[]{ ... }
    var output = new List<double>();
    input.ToObservable().Scan((e, f) => f + e).Subscribe(output.Add);
    Mientras que un poco agradable de código, se requiere un extra de importación

    OriginalEl autor Bruno Garnier

  8. 0

    Aquí un forma de hacerlo usando LINQ:

    double[] doubles = { 1.7, 2.3, 1.9, 4.1, 2.9 };
    var doublesSummed = new List<double>();
    
    Enumerable.Aggregate(doubles, (runningSum, nextFactor) => {
        double currentSum = runningSum + nextFactor;
        doublesSummed.Add(currentSum);
        return currentSum;
    });
    
    doublesSummed.Dump();

    En LINQPad:

    • 4
    • 5.9
    • 10
    • 12.9

    OriginalEl autor kamranicus

  9. 0

    Esto es en realidad bastante sencillo generalizar el uso del generador. Aquí es un nuevo método de extensión llamado Accumulate que funciona como una combinación de Select y Aggregate. Devuelve una nueva secuencia mediante la aplicación de una función binaria a cada elemento de la secuencia y el valor acumulado hasta la fecha.

     public static class EnumerableHelpers 
     {
        public static IEnumerable<U> Accumulate<T, U>(this IEnumerable<T> self, U init, Func<U, T, U> f) 
        {
            foreach (var x in self)
                yield return init = f(init, x);
        }
    
        public static IEnumerable<T> Accumulate<T>(this IEnumerable<T> self, Func<T, T, T> f)
        {
            return self.Accumulate(default(T), f);
        }
    
        public static IEnumerable<double> PartialSums(this IEnumerable<double> self)
        {
            return self.Accumulate((x, y) => x + y);
        }
    
        public static IEnumerable<int> PartialSums(this IEnumerable<int> self)
        {
            return self.Accumulate((x, y) => x + y);
        }
     }

    OriginalEl autor cdiggins

Dejar respuesta

Please enter your comment!
Please enter your name here