Самый «элегантный» способ заполнения словаряиз строки с разделителями - PullRequest
4 голосов
/ 26 января 2012

Я думаю, что те, кто хоть немного разбирается в базовых манипуляциях со строками, в циклах и словарях, могут решить, как заполнить словарь из строки, например:

Черный: # 00000 | Зеленый:# 008000 | (где «черный» - это ключ, а «# 000000» - это значение)

Но какой, на ваш взгляд, самый «элегантный» способ сделать это?Какое наиболее эффективное / более краткое кодирование я могу использовать для его достижения?Пока что у меня есть:

    public static Dictionary<String, String> ThemeColors
    {
        get
        {
            Dictionary<String, String> themeColors = new Dictionary<string, string>();
            foreach (String colorAndCode in GetSettingByName("ThemeColors").ToString().Split('|'))
            {
                themeColors.Add(colorAndCode.Split(':').First(), colorAndCode.Split(':').Last());
            }
            return themeColors;
        }
    }

GetSettingByName ("ThemeColours") возвращает строку выше (выделено жирным шрифтом).

Это функционально, очевидно, все работает, но я хочу убедиться, что яСейчас я начинаю думать не только об этом, но и о том, как найти лучший способ сделать что-то, а не просто заставить его работать.

Могу ли я использовать выход в цикле словаря, например ??

Ответы [ 4 ]

8 голосов
/ 26 января 2012
 public static Dictionary<String, String> ThemeColors
    {
        get
        {
           return GetSettingByName("ThemeColors").ToString().Split('|').ToDictionary(colorAndCode => colorAndCode.Split(':').First(), colorAndCode => colorAndCode.Split(':').Last());
        }
    }

Как предлагается в комментариях более элегантным способом

 public static Dictionary<String, String> ThemeColors2
        {
            get
            {
                return GetSettingByName("ThemeColors").ToString().Split('|').Select(x => x.Split(new[] { ':' }, 2)).ToDictionary(x => x[0], x => x[1]);
            }
        }
4 голосов
/ 26 января 2012

Мне больше всего нравится небольшой вариант вашего подхода:

    public static Dictionary<String, String> ThemeColors
    {
        get
        {
            Dictionary<String, String> themeColors = new Dictionary<string, string>();
            foreach (String colorAndCode in GetSettingByName("ThemeColors").ToString().Split('|'))
            {
                var parts = colorAndCode.Split(':');
                themeColors.Add(parts[0], parts[1]);
            }
            return themeColors;
        }
    }

Единственное отличие состоит в том, что вторая Split() выполняется только один раз, и прямое индексирование выполняется вместо First() и Last().

Теперь ToDictionary() замечательно, когда есть смысл включить что-то в более широкий запрос, и я, конечно, не считаю это неправильным, но это не значит, что ваш подход особенно многословен или что-то в этом роде.

Но мне нравится, что вы легко можете изменить подход к переносу дубликатов (используйте dict[parts[0]] = parts[1], и он будет перезаписывать дубликаты, а не выбрасывать), но также легко изменить бросок для Black:#00000:#010101, проверив размер parts.

В другом направлении, если вам нужно как можно быстрее выполнить синтаксический анализ массивной строки, выбросьте из окна элегантность и замените ее чем-то, что сканирует через токенизацию строки, вместо | используя Split().

Между тем, вышесказанное прекрасно подходит между краткостью и точностью.

3 голосов
/ 26 января 2012

Вот альтернатива, которая использует foreach. Ответы @Haris Hasan и @vcsjones сами по себе изящны. Причина, по которой я показываю это, заключается в том, что я инкапсулирую эту логику в статический класс StringHelper, и этот метод затем можно использовать как расширение строки.

Код из любого ответа выше может быть включен в этот метод.

Пример вызова:

var str = "Black:#00000|Green:#008000|";
Dictionary<string, string> dict = str.NameValuePairsToDictionary(":", "|");


    /// <summary>
    /// convert a string that consists of Name/Value Pairs to a Dictionary.
    /// Name and Value are separated by a given name/value separator
    /// Pairs are separated by a given pair separator token.
    /// example:
    /// Black:#00000|Green:#008000
    /// </summary>
    /// <param name="nvParis">string of name value pairs</param>
    /// <param name="nvSeparator">string that separates the name and value in a name value pair</param>
    /// <param name="pairSeparator">string that separates the name/value pairs from each other</param>
    /// <returns>Dictionary of Name value pairs as string,string</returns>
public static class StringHelper
{
    public static Dictionary<string, string> NameValuePairsToDictionary(this string nvPairs, string nvSeparator, string pairSeparator)
    {
        Dictionary<string, string> dict = new Dictionary<string, string>();

        // default - "\n\r"
        // split name value pairs by separator
        string[] items = nvPairs.Split(pairSeparator.ToCharArray());

        // for each split item, split the name/value pair by 
        // pair separator to add a dictionary item
        foreach (string item in items)
        {
            string[] keyVal = item.Split(nvSeparator.ToCharArray());
            if (keyVal.Length > 1)
                dict.Add(keyVal[0], keyVal[1]);
        }

        return dict;
    }
}
1 голос
/ 26 января 2012
object settings = "Black:#00000|Green:#008000|";

var themeColors = (from setting in ((string)settings).Split('|')
                   where setting != ""
                   select setting.Split(new[]{':'}, 2))
                  .ToDictionary(a => a[0], a => a[1]);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...