Contare dati

di il
10 risposte

Contare dati

Ciao
ho una classe che contiene i dati strutturata così

public class Turno
    {
        public string? Nome { get; set; }
        public string? Qualifica { get; set; }
        public DateTimeOffset? Inizio { get; set; }
        public DateTimeOffset? Fine { get; set; }
        public bool Cambio { get; set; }
        public bool Autorizzato { get; set; }
    }
mi viene passato tramite stringa un dato che serve ad ottenere dalla classe sopra i seguenti dati

public class Conteggio
    {
        public string? Dato { get; set; }
        public int Valore { get; set; }
        public double Ore { get; set; }
    }
il dato passato in stringa è tipo Anno Mese Autorizzato e altri come sotto
quindi faccio questo

public static List<Conteggio> Conteggio(string Campo)
        {
            var r = new Dictionary<string, Conteggio>();
            foreach (var turno in Context.Turni)
                switch (Campo)
                {
                    case "Anno":
                        {
                            conta(r, turno.Inizio?.Year.ToString(), turno);
                            break;
                        }
                    case "Autorizzato":
                        {
                            conta(r, turno.Autorizzato ? " Autorizzato " : " Non Autorizzzato ", turno);
                            break;
                        }
                    case "Nome":
                        {
                            conta(r, turno.Nome, turno);
                            break;
                        }
                    case "Cambio":
                        {
                            conta(r, turno.Cambio ? turno.Inizio == turno.Fine ? " Chiesto cambio " : " Dato cambio " : " Nessun cambio ", turno);
                            break;
                        }
                    case "Mese":
                        {
                            conta(r, turno.Inizio?.Month.ToString(), turno);
                            break;
                        }
                    case "Qualifica":
                        {
                            conta(r, turno.Qualifica, turno);
                            break;
                        }
                }
            return r?.Values.ToList();
        }
        static void conta(Dictionary<string, Conteggio> Dict, string dato, Turno turno)
        {
            if (!Dict.Keys.Contains(dato))
                Dict.Add(dato, new Conteggio() { Dato = dato });
            Dict[dato].Valore++;
            Dict[dato].Ore += (turno.Fine.Value.Subtract(turno.Inizio.Value).TotalHours);
        }

funziona e li conto
non è il massimo ma ho già una idea per farlo meglio ma non è questo il problema
il problema è che voglio contare diversi campi con diverse combinazioni
tipo voglio contare tutti quelli autorizzati o non autorizzati nei diversi mesi
quindi ad esempio [novembre-autorizzati] valore=2 ore=10 [novembre-non autorizzati] valore=3 ore=10 [dicembre-autorizzati] valore=4 ore=16 ecc.
valore è il numero totale conteggiati e ore è il numero di ore fatte
ma non solo con due campi ma un numero e una combinazione definito dalla stringa che ricevo
può essere [anno-autorizzati] [anno-mese-autorizzati] [mese-qualifica-anno] con tutte le combinazioni
Come faccio? devo prevedere tutti i casi nel codice o esiste un altro modo?

grazie in anticipo a tutti quelli che mi vogliono rispondere

10 Risposte

  • Re: Contare dati

    orecchione ha scritto:


    il problema è che voglio contare diversi campi con diverse combinazioni
    Quando si parla di conteggi, ordinamenti, raggruppamenti e "proiezioni", la piattaforma .NET ha uno strumento praticamente unico (nel senso che non si trova altrove) che può venire in aiuto: LINQ.

    Per approfondirlo c'è questo tutorial abbastanza completo.

    Prova a dare un'occhiata, in particolare agli eventuali esempi riportati, per capire come piegarlo eventualmente alle tue esigenze.

    Ciao!
  • Re: Contare dati

    Garzie per la risposta ma anche con linq non riesco a capire come scegliere i campi senza doverli prevedere in compilazione
  • Re: Contare dati

    Linq non permette di usare una stringa come query.
    Servirebbe un dbms
  • Re: Contare dati

    Dunque...
    vediamo se ho capito bene: Tu vuoi raggruppare e contare il numero turni e le ore effettuate in base a dei parametri che ti vengono passati tramite stringa, e questi parametri possono essere quelli che hai inserito nei case, ma al posto di essere uno solo possono essere combinati tra di loro. Ho capito bene? Penso di si, almeno aiutandomi con il codice dovrebbe essere questo che vuoi.
    A questo punto probabilmente faresti prima utilizzando GroupBy di Linq.
    Ovviamente dovrai preparare i dati in modo da poterli già raggruppare secondo le tue esigenze.
    Ora il vero problema:
    GroupBy ha la necessità che li venga specificato il tipo in compilazione, per cui comunque dovresti prevedere tutte le combinazioni, e non sarebbero poche... a meno che non usi un po di reflection. Dovrei avere giusto un pezzo di codice che uso in un programma fatto diverso tempo fa. Magari potrebbe essere una base di partenza:
    [CODE] public static class LinqExtension { public static IEnumerable<IGrouping<object, T>> GroupBy<T>(this IEnumerable<T> list, params string[] propertyNames) { var properties = propertyNames.Select(s => typeof(T).GetProperty(s)).ToArray(); var propertyTypes = properties.Select(s => s.PropertyType).ToArray(); var type = typeof(Tuple).Assembly.GetType("System.Tuple`" + properties.Length); var genericType = type.MakeGenericType(propertyTypes); var param = Expression.Parameter(typeof(T), "elements"); var constructor = genericType.GetConstructor(propertyTypes); var obj = Expression.New(constructor, properties.Select(s => Expression.Property(param, s))); var expr = Expression.Lambda<Func<T, object>>(obj, param); return list.GroupBy(expr.Compile()); } } Si tratta di un metodo d'estensione, quindi lo puoi usare nella query linq una volta inserito nel tuo progetto/namespace.
    Ad esempio nel tuo caso basta una cosa del genere : [CODE] public static List<Conteggio> Conteggio(params string[] Campi) { return Context.Turni.OrderBy(o => o.Inizio.Value.Year).ThenBy(t => t.Inizio.Value.Month).Select(s => new { Anno = s.Inizio.Value.Year.ToString(), Autorizzato = s.Autorizzato ? " Autorizzato " : " Non autorizzato ", Nome = s.Nome, Cambio = s.Cambio ? s.Inizio == s.Fine ? " Chiesto cambio " : " Dato cambio " : " Nessun cambio ", Mese = s.Inizio.Value.ToLocalTime().ToString("MMM"), Qualifica = s.Qualifica, Ore = s.Fine.Value.Subtract(s.Inizio.Value) }).GroupBy(Campi).Select(s => new Conteggio() { Dato = s.Key.ToString(), Valore = s.Count(), Ore = new TimeSpan(s.Sum(sum => sum.Ore.Ticks)).TotalHours }).ToList(); }
  • Re: Contare dati

    orecchione ha scritto:


    Garzie per la risposta ma anche con linq non riesco a capire come scegliere i campi senza doverli prevedere in compilazione
    Credo di aver capito cosa intendi, ma eventualmente prova a esemplificare con un pezzo di codice abbozzato, giusto per capire qual è il punto che ti ostacola la buona riuscita di quello che vuoi ottenere.
  • Re: Contare dati

    Ho provato con group t by new {t.Anno, t.Mese} ma devo prevedere in compilazione
  • Re: Contare dati

    orecchione ha scritto:


    Ho provato con group t by new {t.Anno, t.Mese} ma devo prevedere in compilazione
    Ok, ma quel raggruppamento puoi farlo in modo "condizionato", ossia inserirlo in un blocco dove venga applicato se è stato scelto un certo tipo di raggruppamento.
    
    var items = new List<Turno>();
    
    // ...
    
    var query = items.AsEnumerable();
    
    // ...
    
    switch(campo) 
    {
      case "Anno":
        query = query.GroupBy(s => s.Anno);
        break;
        // ...
    }
    
    // ...
    
    Si tratta solo di pseudocodice per rendere l'idea.

    Ciao!
  • Re: Contare dati

    Ma così devo prevederlo nel codice con lo switch o sbaglio?
  • Re: Contare dati

    @orecchione
    ti ho mostrato come fare qualche post sopra. Devi inserire la classe statica nel progetto e dopo puoi usare GroupBy con le stringhe direttamente.
    Ad esempio:
    
    var result = Conteggio("Anno","Mese");
    '... Dato=(2021,Gennaio), Valore=300, ore= 900
    '... Dato=(2022,Maggio), Valore=355, ore= 840
    ...
    
    var result = Conteggio("Qualifica","Mese");
    '... Dato=(qualifica1,Gennaio), Valore=25, ore= 80
    '... Dato=(qualifica1,Maggio), Valore=231, ore= 475
    '... Dato=(qualifica2,Maggio), Valore=51, ore= 125
    
    ...
    
    var result = Conteggio("Anno", "Qualifica", "Mese");
    '... Dato=(2021,qualifica1,Gennaio), Valore=23, ore= 50
    '... Dato=(2021,qualifica1,Maggio), Valore=123, ore= 250
    '... Dato=(2022,qualifica1,Gennaio), Valore=13, ore= 35
    '... Dato=(2022,qualifica1,Maggio), Valore=40, ore= 65
    
  • Re: Contare dati

    Non avevo capito come usarlo ma funziona grazie ho risolto
Devi accedere o registrarti per scrivere nel forum
10 risposte