简体   繁体   中英

What is the best, more practical way to write such an entry with nested dictionaries? Which design pattern to use? C#

There is a lot of data in the database, and it is necessary to produce statistics (find the average number of each operation per day by each user of the application) using c # collections. In my opinion, it is necessary to use dictionaries:

var dict = new Dictionary<long?, Dictionary<DateTime, Dictionary<OperationsGroupType, int>>>();

Please advise a more practical way to write it. As it looks strange. Thank you

I wrote a function:

public void D()
        {
            var dict = new Dictionary<long?, Dictionary<DateTime, Dictionary<OperationsGroupType, int>>>();
            int pageNumber = 0;
            int pageSize = 5;
            int pageCount = 1;

            while (pageNumber < pageCount)
            {
                int count;
                foreach (OperationData op in OperationService.GetPage(pageNumber, pageSize, out count))
                    if(op.PerformedBy.HasValue)
                        if(op.PerformedDate.HasValue)
                            if (dict.ContainsKey(op.PerformedBy))
                                if (dict[op.PerformedBy].ContainsKey(op.PerformedDate.Value.Date.Date))
                                    if (dict[op.PerformedBy][op.PerformedDate.Value.Date.Date.Date.Date].ContainsKey(op.Type)) dict[op.PerformedBy][op.PerformedDate.Value.Date.Date.Date.Date][op.Type]++;
                                    else dict[op.PerformedBy][op.PerformedDate.Value.Date.Date.Date.Date].Add(op.Type, 1);
                                else dict[op.PerformedBy].Add(op.PerformedDate.Value.Date.Date.Date.Date, new Dictionary<OperationsGroupType, int> { { op.Type, 1 } });
                            else dict.Add(op.PerformedBy, new Dictionary<DateTime, Dictionary<OperationsGroupType, int>> { { op.PerformedDate.Value.Date.Date.Date.Date, new Dictionary<OperationsGroupType, int> { { op.Type, 1 } } } });

                pageCount = (count - 1) / pageSize + 1;
                pageNumber++;
            }

            foreach (var item in dict)
            {
                var opDateDict = new Dictionary<DateTime, int>();
                foreach (var operDate in item.Value) opDateDict.Add(operDate.Key, operDate.Value.Sum(count => count.Value));

                SystemLogger.Instance.WriteErrorTrace(String.Format("Average number of user operations {0} per day: {1}\n", item.Key, opDateDict.Values.Sum() / opDateDict.Count));
            }
        }
OperationsGroupType - this enum

Please tell me how to replace the dictionary with a more practical design? Which pattern is best for solving this problem?

It's terribly difficult to say what's best or most practical - and that's because you didn't really define what you mean by "best" or "practical".

I'm going to define them as minimal code and minimal repetition.

To start with I created these extension methods:

public static class Ex
{
    public static R Ensure<T, R>(this Dictionary<T, R> @this, T key) where R : new
    {
        if (@this.ContainsKey(key))
            return @this[key];
        else
        {
            var r = new R();
            @this[key] = r;
            return r;
        }
    }

    public static R Ensure<T, R>(this Dictionary<T, R> @this, T key, Func<R> factory)
    {
        if (@this.ContainsKey(key))
            return @this[key];
        else
        {
            var r = factory();
            @this[key] = r;
            return r;
        }
    }
}

With those I can rewrite you code like this:

foreach (OperationData op in OperationService.GetPage(pageNumber, pageSize, out count))
{
    if (op.PerformedBy.HasValue)
        if (op.PerformedDate.HasValue)
        {
            dict.Ensure(op.PerformedBy).Ensure(op.PerformedDate.Value.Date).Ensure(op.Type, () => 0);
            dict[op.PerformedBy][op.PerformedDate.Value.Date][op.Type]++;
        }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM