将字符串数组转换为字符串字典的最优雅方法

58

有没有内置函数可以将字符串数组转换为字符串字典,还是需要在这里进行循环处理?


不管你想要的结构是什么,最终你都会得到一个循环。无论你怎么看,这是不可避免的。 - Kyle Rosendo
6
无论何时都会有一个循环存在,但是LINQ可以帮你隐藏它——也就是说,你不需要在你的代码中写出这个循环。 - Jon Skeet
9个回答

122

假设您正在使用.NET 3.5,您可以将任何序列(即IEnumerable<T>)转换为字典:

var dictionary = sequence.ToDictionary(item => item.Key,
                                       item => item.Value)

其中KeyValue是你想要作为键和值的属性。如果项目本身就是你想要的值,你可以仅指定一个用于键的投影。

例如,如果您想将每个字符串的大写版本映射到原始版本,则可以使用以下方式:

var dictionary = strings.ToDictionary(x => x.ToUpper());

在你的情况下,你想要键和值是什么?

如果你只想要一个集合(例如,你可以检查它是否包含特定的字符串),你可以使用:

var words = new HashSet<string>(listOfStrings);

那种风险总是存在的,除非你在查找重复键之前进行检查。 - Dykam
1
请看shA.t的帖子,你真的需要使用IndexOf来获取字典中的键。我同意shA.t的观点,人们正在寻找的是一个Dictionary<int, string>,其中键是旧数组的索引。 - mike
1
@mike:不,使用IndexOf是个坏主意。如果目的是创建一个Dictionary<int, string>,我会使用array.Select((value, index) => new { value, index }).ToDictionary(pair => pair.index, pair => pair.value);。否则,如果数组中有多个相同的字符串,由于键不唯一,你将失败。 - Jon Skeet
@mike:是的,它正在创建一个字典。OP从未指定过什么类型的字典 - 如今,这个问题可能已经被关闭,因为不清楚。尽管如此,我的回答显然足够帮助OP,因为他们接受了它 - 我认为他们比你更适合知道什么是合适的。 - Jon Skeet
1
John Skeet:我的困惑在于输入,而不是输出。OP要求转换“字符串数组”,而你给出了将“任何序列(即IEnumerable<T>)”转换的示例,我不清楚你如何将string[]转换为IEnumerable,因为你的示例sequence.ToDictionary(item => item.Key,item => item.Value)肯定无法在序列(输入)是字符串数组的情况下工作。 - mike
显示剩余5条评论

21
你可以使用LINQ来完成这个任务,但首先需要回答Andrew提出的问题(你的键和值是什么):
using System.Linq;

string[] myArray = new[] { "A", "B", "C" };
myArray.ToDictionary(key => key, value => value);

结果是一个像这样的字典:

A -> A
B -> B
C -> C

15

在我看来,当我们说一个 Array 时,我们指的是一个值列表,我们可以通过调用其索引(value => array[index])来获取其中的一个值。因此,一个正确的字典应该具有索引作为键。

感谢 @John Skeet,正确实现这一点的方法是:

var dictionary = array
    .Select((v, i) => new {Key = i, Value = v})
    .ToDictionary(o => o.Key, o => o.Value);

另一种方法是使用类似于这样的扩展方法:

public static Dictionary<int, T> ToDictionary<T>(this IEnumerable<T> array)
{
    return array
        .Select((v, i) => new {Key = i, Value = v})
        .ToDictionary(o => o.Key, o => o.Value);
}

2
这样做会a)效率低下;b)如果数组中出现相同的值,则会失败。您可以使用提供索引的Select重载来更有效且可靠地执行此操作。 - Jon Skeet
谢谢,我已经按照你提供的参考使用了 Select - shA.t

5

如果您需要一个没有值的字典,您可能需要使用HashSet

var hashset = new HashSet<string>(stringsArray);

3

你的意思是什么?

字典是一种哈希表,其中键映射到值。

你的键是什么,你的值是什么?

foreach(var entry in myStringArray)
    myDictionary.Add(????, entry);

2

我假设这个问题与键和值交替的数组有关。当我尝试将Redis协议转换为字典时,我遇到了这个问题。

private Dictionary<T, T> ListToDictionary<T>(IEnumerable<T> a)
{
    var keys = a.Where((s, i) => i % 2 == 0);
    var values = a.Where((s, i) => i % 2 == 1);
    return keys
        .Zip(values, (k, v) => new KeyValuePair<T, T>(k, v))
        .ToDictionary(kv => kv.Key, kv => kv.Value);
}

0
            Dictionary<int, string> dictionaryTest = new Dictionary<int, string>();

            for (int i = 0; i < testArray.Length; i++)
            {
                dictionaryTest.Add(i, testArray[i]);
            }

            foreach (KeyValuePair<int, string> item in dictionaryTest)
            {


                Console.WriteLine("Array Position {0} and Position Value {1}",item.Key,item.Value.ToString()); 
            }

1
不要仅仅呈现代码!添加一些描述性文本来说明这个解决方案如何最好地回答问题,将提高答案的长期价值,并有助于在审核过程中防止其被删除。 - NightOwl888
这正是我所需要的,谢谢!我想不出来。 - Mo Star

0

这个问题不是很清楚,但是如果提供的字符串带有一些字符来支持Dictionary<Key,Value>对,那么是可以将字符串转换为Dictionary的。

因此,如果一个字符串像a=first;b=second;c=third;d=fourth,你可以首先根据;进行分割,然后再根据=进行分割,以创建一个Dictionary<string,string>。下面的扩展方法也是这样做的。

public static Dictionary<string, string> ToDictionary(this string stringData, char propertyDelimiter = ';', char keyValueDelimiter = '=')
{
    Dictionary<string, string> keyValuePairs = new Dictionary<string, string>();
    Array.ForEach<string>(stringData.Split(propertyDelimiter), s =>
        {
            if(s != null && s.Length != 0)
                keyValuePairs.Add(s.Split(keyValueDelimiter)[0], s.Split(keyValueDelimiter)[1]);
        });

    return keyValuePairs;
}

并可以像使用这样

var myDictionary = "a=first;b=second;c=third;d=fourth".ToDictionary();

由于扩展方法的默认参数是;=


0

您可以通过以下方式从 IEnumerable<T>(包括数组)创建字典:

var dictionary = myEnumerable.ToDictionary(element => element.Key,
                                           element => element.Value)

其中KeyValue是您想要存储在每个字典元素中的键和值。可用于.NET Framework 3.5+/.NET Core 1.0+/.NET 5.0+。官方文档。

如果您希望字典是原始可枚举对象中的元素:

   var dictionary = myEnumerable.ToDictionary(element => element.Key)

如果您只需要高性能的集合操作,您可以尝试使用:

var words = new HashSet<string>(listOfStrings);

简单来说,HashSet类可以被视为一个没有值的Dictionary<TKey,TValue>集合。官方文档。 (请注意,'sequence'在一个完全无关的对象中。 最初提交了一个现有答案的编辑,但被作者拒绝了,所以单独发布,包括链接到官方Microsoft文档。)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接