Question

Disons que j'ai cette classe Person amputée:

class Person
{
    public int Age { get; set; }
    public string Country { get; set; }

    public int SOReputation { get; set; }
    public TimeSpan TimeSpentOnSO { get; set; }

    ...
}

Je peux alors le groupe sur Age et Country comme ceci:

    var groups = aListOfPeople.GroupBy(x => new { x.Country, x.Age });

Ensuite, je peux sortie tous les groupes avec leurs totaux de réputation comme ceci:

foreach(var g in groups)
    Console.WriteLine("{0}, {1}:{2}", 
        g.Key.Country, 
        g.Key.Age, 
        g.Sum(x => x.SOReputation));

Ma question est, comment puis-je obtenir une somme de la propriété TimeSpentOnSO? La méthode de Sum ne fonctionnera pas dans ce cas car il est seulement pour int et tel. Je pensais que je pouvais utiliser la méthode Aggregate, mais juste au sérieux ne peut pas comprendre comment l'utiliser ... J'essaie toutes les propriétés des types et des types dans diverses combinaisons, mais le compilateur juste ne le reconnaît pas.

foreach(var g in groups)
    Console.WriteLine("{0}, {1}:{2}", 
        g.Key.Country, 
        g.Key.Age, 
        g.Aggregate(  what goes here??  ));

Ai-je complètement missunderstood la méthode globale? Ou ce qui se passe? Est-il une autre méthode que je devrais utiliser à la place? Ou dois-je écrire ma propre variante de Sum pour TimeSpans?

Et pour ajouter au désordre, si personne est une classe anonyme, résultat de par exemple un Select ou une déclaration de GroupJoin?


Juste pensé que je pouvais faire le travail de la méthode de Aggregate si je faisais un Select sur la propriété TimeSpan premier ... mais je trouve ce genre de ennuyeux ... ne me sens pas que je comprends cette méthode du tout .. .

foreach(var g in groups)
    Console.WriteLine("{0}, {1}:{2}", 
        g.Key.Country, 
        g.Key.Age, 
        g.Select(x => x.TimeSpentOnSO)
        g.Aggregate((sum, x) => sum + y));
Était-ce utile?

La solution 3

Une combinaison de réponses Chris et Daniels résolu pour moi. Je avais besoin d'initialiser le TimeSpan, et je l'ai fait les choses dans le mauvais ordre. La solution est:

foreach(var g in groups)
    Console.WriteLine("{0}, {1}:{2}", 
        g.Key.Country, 
        g.Key.Age, 
        g.Aggregate(TimeSpan.Zero, (sum, x) => sum + x.TimeSpentOnSO));

Merci!

Et aussi ... D'oh!

Autres conseils

List<TimeSpan> list = new List<TimeSpan>
    {
        new TimeSpan(1),
        new TimeSpan(2),
        new TimeSpan(3)
    };

TimeSpan total = list.Aggregate(TimeSpan.Zero, (sum, value) => sum.Add(value));

Debug.Assert(total.Ticks == 6);
g.Aggregate(TimeSpan.Zero, (i, p) => i + p.TimeSpentOnSO)

Fondamentalement, le premier argument des agrégats est un initialiseur, qui est utilisé en tant que la première valeur de « i » dans la fonction passée dans le second argument. Il va itérer sur la liste, et chaque fois, « i » contiendra le total à ce jour.

Par exemple:

List<int> nums = new List<int>{1,2,3,4,5};

nums.Aggregate(0, (x,y) => x + y); // sums up the numbers, starting with 0 => 15
nums.Aggregate(0, (x,y) => x * y); // multiplies the numbers, starting with 0 => 0, because anything multiplied by 0 is 0
nums.Aggregate(1, (x,y) => x * y); // multiplies the numbers, starting with 1 => 120

Vous pouvez écrire TimeSpan méthode Sum ...

public static TimeSpan Sum(this IEnumerable<TimeSpan> times)
{
    return TimeSpan.FromTicks(times.Sum(t => t.Ticks));
}
public static TimeSpan Sum<TSource>(this IEnumerable<TSource> source,
    Func<TSource, TimeSpan> selector)
{
    return TimeSpan.FromTicks(source.Sum(t => selector(t).Ticks));
}

Vous pouvez également MiscUtil a des méthodes de Sum génériques compatibles, donc Sum devrait fonctionner sur un TimeSpan très bien (car il y a un opérateur TimeSpan+TimeSpan=>TimeSpan défini).

Juste s'il vous plaît ne me dites pas le numéro ... il me faire peur ...

Vous pouvez résumer sur une des propriétés totales du TimeSpan. Par exemple, vous pouvez obtenir les TotalHours représentés du temps consacré à SO comme ceci:

g.Sum(x => x.SOReputation.TotalHours)

Je crois que cela vous donne le résultat que vous êtes à la recherche, mais avec la mise en garde que vous auriez à mettre les unités de mesure en fonction de ce dont vous avez besoin (heures, minutes, secondes, jours, etc.)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top