Резюме вывод информации о ценах


Эта функция используется в веб-приложении ASP.NET написан на C#. Она широко используется для вывода сводной информации по некоторым ценам, выбранных пользователем. Мы пытаемся уменьшить сколько надо по горизонтали.

Вот оригинал функции:

    private static Dictionary<int, string> Cache = new Dictionary<int, string> {{ 1, "Adult" }, { 2, "Child" }};

    public string Build(List<int> priceTypeIds)
    {
        if (session == null)
        {
            return "";
        }

        var uniquePriceTypeIds = priceTypeIds.Distinct();

        var result = new List<string>();

        foreach (var priceTypeId in uniquePriceTypeIds)
        {
            var count = priceTypeIds.Count(x => x == priceTypeId);

            var description = Cache[priceTypeId];

            result.Add($"{count} {description}");
        }

        return string.Join(", ", result);
    }

Я переписал функцию, чтобы исключить количеством сцепление. Но

private static Dictionary<int, string> Cache = new Dictionary<int, string> {{ 1, "Adult" }, { 2, "Child" }};

public static string CreateSummary()
{
    var sb = new StringBuilder();

    List<int> sample = new List<int> { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 };

    foreach (var priceTypeId in sample.Distinct())
    {
        if (sb.Length > 0)
        {
            sb.Append(',');
            sb.Append(' ');
        }

        sb.Append('(');
        sb.Append(Sample.Count(x => x == priceTypeId));
        sb.Append(')');
        sb.Append(' ');
        sb.Append(Cache[priceTypeId.ToString()]);
    }

    return sb.ToString();
}

Образец данных во второй функцией является типичным случаем применения как у нас классы вам приобрести с 20-30 детьми в одной транзакции вместе с сопровождающими.



152
0
задан 15 марта 2018 в 11:03 Источник Поделиться
Комментарии
2 ответа

Как я вижу, ваш код работает нормально, как это. Хотя вы могли бы улучшить его немного, добавляя каждый priceTypeId в одной операции appendFormat как в:

string CreateSummary<T>(IEnumerable<T> sample, Dictionary<string, int> cache)
{
var sb = new StringBuilder();

foreach (var priceTypeId in sample.Distinct())
{
sb.AppendFormat("({0}) {1}, ", sample.Count(x => x.Equals(priceTypeId)), cache[priceTypeId.ToString()]);
}

sb.Length -= 2;

return sb.ToString();
}

Как он показывает, я сделал функцию универсальной (и догадались, что кэш-это словарь?). Последний раздражает запятая (',') удаляется sb.Length -= 2;.


Дальнейшее улучшение может быть использовать группировку вместо distinct():

string CreateSummary<T>(IEnumerable<T> sample, Dictionary<string, int> cache)
{
var sb = new StringBuilder();

foreach (var group in sample.GroupBy(s => s))
{
sb.AppendFormat("({0}) {1}, ", group.Count(), cache[group.Key.ToString()]);
}

sb.Length -= 2;

return sb.ToString();
}


Чтобы избежать спиливания длины можно использовать перечислитель, а не такой, чтобы обращаться к первой группе отдельно:

string CreateSummary<T>(IEnumerable<T> sample, Dictionary<string, int> cache)
{
var sb = new StringBuilder();

var groups = sample.GroupBy(s => s);
var enumer = groups.GetEnumerator();
if (enumer.MoveNext())
{
sb.AppendFormat("({0}) {1}", enumer.Current.Count(), cache[enumer.Current.Key.ToString()]);
while (enumer.MoveNext())
{
sb.AppendFormat(", ({0}) {1}", enumer.Current.Count(), cache[enumer.Current.Key.ToString()]);
}
}

return sb.ToString();
}


Мои собственные решения будут аналогичны tinstaafls:

string CreateSummary<T>(IEnumerable<T> sample, Dictionary<string, int> cache)
{
return string.Join(", ", sample.GroupBy(s => s).Select(gr => $"({gr.Count()}) {cache[gr.Key.ToString()]}"));
}

1
ответ дан 16 марта 2018 в 10:03 Источник Поделиться

Мне кажется, что ваша проблема могла бы сделать с немного больше LINQ и оператор конкатенации. А конкретно group пункт. Вот один из способов это может быть сделано:

public static string Method2()
{
List<int> sample = new List<int> { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 };

var data = String.Join(", ", (from int i in sample
group i by i into g
select $"({g.Count()}) {Cache[g.Key.ToString()]}"));

return data;
}

Эффективность, я думаю, будет лучше, чем то, что вы до сих пор Distinct и каждый Count дополнительные итерации над данными, но оно должно быть испытано, чтобы быть уверенным.

Это, безусловно, имеет преимущество быть более кратким.

Имея строку формата в одном месте делает его легче увидеть, что происходит.

Если вам нужны данные анализируются, вместо одной длинной строкой, в какой-то момент, снимая String.Join часть оставить IEnumerable<string>.

3
ответ дан 16 марта 2018 в 05:03 Источник Поделиться