Посоветуйте оптимизировать следующий код лучшим способом

#c# #linq #unity3d

Вопрос:

У меня есть некоторые данные, хранящиеся в словаре, где значения в основном представляют собой список объектов с небольшим количеством атрибутов в них. Прямо сейчас я просматриваю следующее, чтобы получить данные, хранящиеся в определенном атрибуте. Затем эти данные добавляются в выпадающий список (unity UI dropdown)

 foreach (KeyValuePair<string, List<NameIDValuePair>> kvp in TeamValuePair)
            {
                List<NameIDValuePair> list = kvp.Value;

                if(kvp.Key == teamNames.options[teamNames.value].text)
                {
                    foreach (var rec in list)
                    {
                        screenNamesDropDown.options.Add(new TMP_Dropdown.OptionData { text = rec.ScreenName });
                    }
                }
            }
 

Имена команд и имена экранов — это выпадающие элементы, являющиеся частью моего пользовательского интерфейса Unity.

Структура NameIdValuePair выглядит следующим образом:

 public class NameIdValuePair 
        {
            public string ScreenName { get; private set; }

            public string ScreenId { get; private set; }
        }
 

Я хотел бы оптимизировать этот фрагмент кода лучшим способом, используя linq — чтобы он был немного более читабельным. Поскольку я довольно новичок в linq, я не совсем уверен, правильно ли я использую ключевые слова при поиске предложений, но пока у меня не было большого успеха в поиске какого-либо полезного предложения.

Спасибо

Комментарии:

1. Лучший способ ответить на этот вопрос — опубликовать это в Code review

2. LINQ — отличный инструмент для фильтрации или выбора коллекций, а не для использования результирующего запроса. Ваш код просто показывает, как вы используете результат, который у вас уже есть. Так что нечего оптимизировать с помощью LINQ. Другими словами, LINQ мог бы помочь в создании этого словаря, но он не может заменить foreach цикл.

3. почему вы повторяете словарь TeamValuePair ? ключ не может быть продублирован, поэтому код внутри if фактически выполняется один раз (если ключ существует)… вы можете получить список, просто используя индексатор dictionarys напрямую с заданным ключом (при условии, что ключ существует)

4. Вместо того, чтобы зацикливать словарь, попробуйте TeamValuePair.TryGetValue(teamNames.options[teamNames.value].text, out var list) получить нужный вам единый список, или, если для ключа нет записи, он вернет false, и вы можете пропустить его

5. LINQ отлично подходит для написания компактных, выразительных запросов. Но он опирается на абстракции, которые имеют некоторые накладные расходы. Поэтому, если производительность является проблемой, это редко бывает лучшей альтернативой. И вообще, читаемость часто трудно сочетать с оптимизацией, высокооптимизированный код может быть практически невозможно понять без очень подробных комментариев.

Ответ №1:

Как упоминалось ранее, вместо цикла a Dictionary — где мы уже знаем, что ключи уникальны — вы могли бы просто использовать Dictionary.TryGetValue

 // do this only once! 
var key = teamNames.options[teamNames.value].text;

if (TeamValuePair.TryGetValue(key, out var list))
{
    foreach(var item in list)
    {
        screenNamesDropDown.options.Add(new TMP_Dropdown.OptionData(item.ScreenName));
    }
}
 

и тогда на самом деле единственное место, где вы могли бы использовать Linq, если вы действительно этого хотите, возможно, будет в

 var key = teamNames.options[teamNames.value].text;

if (TeamValuePair.TryGetValue(key, out var list))
{
    screenNamesDropDown.options.AddRange(list.Select(item => new TMP_Dropdown.OptionData(item.ScreenName)));
}
 

хотя, если это улучшает чтение, это сомнительно.

И в целом вопрос также будет заключаться в том, всегда ли вы хотите Add ( AddRange ) к screenNamesDropDown.options или, если вы, возможно, захотите фактически заменить параметры. Тогда вместо AddRange того, чтобы вы могли бы сделать

 screenNamesDropDown.options = list.Select(item => new TMP_Dropdown.OptionData(item.ScreenName)).ToList();
 

Комментарии:

1. Спасибо за ваш комментарий. Я хотел включить linq, просто чтобы посмотреть, есть ли лучший способ фильтровать / выбирать значения и помещать их в список с помощью ToList() и добавлять их непосредственно в мой выпадающий список, используя свойство AddOptions, предлагаемое Unity UI Dropdown, которое может использовать список строк. В моем случае у меня есть два выпадающих списка, где первый содержит имена всех ключей. И на основе ключа, выбранного в первом выпадающем списке, имена экранов должны быть извлечены и заполнены из словаря и включены в выпадающий список с помощью функции AddOptions, а не с помощью опций. Добавить

2. Я протестирую ваш фрагмент кода и свяжусь с вами через некоторое время. Еще раз спасибо 🙂

3. Спасибо. Мне было действительно полезно перестроить свой код лучшим образом 🙂