c# - 使用int和string将数组转换为字典c#

标签 c# arrays dictionary

我有一个包含字符串和字典的字符串数组。

String [] str_array;
Dictionary<int, string> dict = new Dictionary<int, string>();

dict = str_array.toDictionary();

如何将数组放入具有 int 和 String 的字典中? 我已经看过所有这些使用 bool 的示例,但我需要 int 和 string。

int(键)将只是字典(dict.count)的实际位置,值将是数组在该位置的值。

编辑:感谢所有答案,但我不想遍历数组。我假设使用 array.toDictionary 的性能会比遍历数组并将数组的值分配给字典更好。数组可能有 5k 个元素。

edit2:原因是我必须将字典传递给方法……这是必需的。我所有的值都在一个简单的数组中。

edit3:最重要的是性能。也许遍历数组并将值分配给 dict 比 array.toDictionary 更快,但问题是我没有那么小的代码来对两者进行基准测试。

最佳答案

首先 - 你的性能问题很有趣并且有点过早优化的味道 - 正如这个答案将显示的那样,你可能会看到 for 之间的性能差异几毫秒。循环和 ToDictionary .

除非您在实时系统中运行它,否则我看不出有什么问题。

关于节目 - 以下是我能想到的三种(半)不同的构建字典的粗略基准(只有真实世界的时间是可靠的)。第一个使用 for循环,第二个做同样的事情但不使用数组的 Length属性(property)(仅用于利息);第三次和第四次使用ToDictionary ;一个使用 Select一个使用计数器变量(混合):

[TestMethod]
public void SomeBenchmark()
{
    List<double> forLoopTimes = new List<double>();
    List<double> forLoop2Times = new List<double>();
    List<double> toDictionaryTimes = new List<double>();
    List<double> hybridTimes = new List<double>();

    string[] array = Enumerable.Range(0, 5000).Select(i => i.ToString()).ToArray();

    Dictionary<int, string> dictionary;

    int runCount = 5000;
    int arrayLen = array.Length;

    while (runCount-- != 0)
    {
        Stopwatch sw = Stopwatch.StartNew();
        dictionary = new Dictionary<int, string>();
        for (int i = 0; i < array.Length; i++)
        {
            dictionary[i] = array[i];
        }
        sw.Stop();
        forLoopTimes.Add(sw.Elapsed.TotalMilliseconds);

        sw.Restart();
        dictionary = new Dictionary<int, string>();
        for (int i = 0; i < arrayLen; i++)
        {   //same as before - but using arrayLen instead of property
            dictionary[i] = array[i];
        }
        sw.Stop();
        forLoop2Times.Add(sw.Elapsed.TotalMilliseconds);

        sw.Restart();
        dictionary = array.Select((s, i) => new { Key = i, Value = s }).ToDictionary(v => v.Key, v => v.Value);
        sw.Stop();
        toDictionaryTimes.Add(sw.Elapsed.TotalMilliseconds);

        int counter = 0;
        sw.Restart();
        dictionary = array.ToDictionary(s => counter++, s => s);
        sw.Stop();
        hybridTimes.Add(sw.Elapsed.TotalMilliseconds);
    }
    Console.WriteLine("for loop average: {0} milliseconds", forLoopTimes.Average());
    Console.WriteLine("for loop(2) average: {0} milliseconds", forLoop2Times.Average());
    Console.WriteLine("ToDictionary average: {0} milliseconds", toDictionaryTimes.Average());
    Console.WriteLine("Hybrid average: {0} milliseconds", hybridTimes.Average());
}

结果(发布版本,在我的戴尔 2.4Ghz 工作站上运行大约需要 20 秒):

For loop average: 0.28880804 milliseconds

For loop(2) average: 0.2773845 milliseconds

ToDictionary average: 0.479094339999998 milliseconds

Hybrid average: 0.353655779999999 milliseconds

所以 for loop 无疑更快 - 至少比最近的 ToDictionary 快 22%执行。我用 100,000 个元素进行了尝试,然后它达到了大约 30%。

注意第二个for循环结果 - 似乎暗示绕过 Length属性(property)是个好主意。事实上,我已经连续运行了 4 次,结果如下(包括上面的第一个):

For loop: 0.28880804, 0.28562478, 0.283770739999999, 0.287241679999999

For loop(2): 0.2773845, 0.27621306, 0.27869996, 0.27962916

ToDictionary: 0.479094339999998, 0.476417939999997, 0.476162219999997, 0.475776479999997

Hybrid: 0.353655779999999, 0.3583224, 0.352022739999998, 0.349865779999999

但是,我也看到至少一个基准测试的结果翻转了 - 证明了这种基准测试在很大程度上是毫无意义的。实际上,我们也应该为每个测试生成一个不同的数组,以避免缓存等。

还有一个选择。

如果您调用的方法接受 IDictionary<int, string> (注意——界面);而不是 Dictionary<int, string>您可以创建一个简单的包装器类型来实现接口(interface)的必要成员,从而完全避免投影到字典中的需要;只要只需要某些成员。这是一个几乎完整的实现:

public class FakeDictionary : IDictionary<int, string>
{
    private readonly string[] _array;

    public FakeDictionary(string[] array)
    {
        _array = array;
    }

    #region IDictionary<int,string> Members

    public void Add(int key, string value)
    {
        throw new NotSupportedException();
    }

    public bool ContainsKey(int key)
    {
        return key >= 0 && key < _array.Length;
    }

    public ICollection<int> Keys
    {
        get { return Enumerable.Range(0, _array.Length).ToArray(); }
    }

    public bool Remove(int key)
    {
        throw new NotSupportedException();
    }

    public bool TryGetValue(int key, out string value)
    {
        value = null;
        if (key >= 0 && key < _array.Length)
        {
            value = _array[key];
            return true;
        }
        return false;
    }

    public ICollection<string> Values
    {
        get { return _array; }
    }

    public string this[int key]
    {
        get
        {
            try
            {
                return _array[key];
            }
            catch (ArgumentOutOfRangeException ex)
            {
                throw new KeyNotFoundException("Invalid key", ex);
            }
        }
        set //note - can't be used to add items
        {
            try
            {
                _array[key] = value;
            }
            catch (ArgumentOutOfRangeException ex)
            {
                throw new KeyNotFoundException("Invalid key", ex);
            }
        }
    }

    #endregion

    #region ICollection<KeyValuePair<int,string>> Members

    public void Add(KeyValuePair<int, string> item)
    {
        throw new NotSupportedException();
    }

    public void Clear()
    {
        throw new NotSupportedException();
    }

    public bool Contains(KeyValuePair<int, string> item)
    {
        return ContainsKey(item.Key) && _array[item.Key].Equals(item.Value);
    }

    public void CopyTo(KeyValuePair<int, string>[] array, int arrayIndex)
    {
        //too much for an SO answer.
        throw new NotImplementedException();
    }

    public int Count
    {
        get { return _array.Length; }
    }

    public bool IsReadOnly
    {
        //technically it's not - because we can modify individual elements - 
        //but at the collection-level it is
        get { return true; }
    }

    public bool Remove(KeyValuePair<int, string> item)
    {
        throw new NotSupportedException();
    }

    #endregion

    #region IEnumerable<KeyValuePair<int,string>> Members

    public IEnumerator<KeyValuePair<int, string>> GetEnumerator()
    {
        throw new NotImplementedException();
    }

    #endregion

    #region IEnumerable Members

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        throw new NotImplementedException();
    }

    #endregion
}

关于c# - 使用int和string将数组转换为字典c#,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11523175/

相关文章:

Python csv(两列: key/value) to Dictionary

python - 如何计算特定周数之间的周数?

c# - 如何使用 C# 从 ASP.Net 中的数据库中获取最新记录?

c# - 带反向引用的正则表达式前瞻

java - 你如何在 Java 中将某些东西表示为空?

java - 将 CharArray 传递给方法

c# - float 是否可以通过 double 往返而不损失精度?

c# - 为什么我的 .NET 应用程序在从网络驱动器运行时会崩溃?

java - 有没有一种方法可以在 Java 的一个数组元素中包含多行文本?

swift - 制作一个键为 "Type"的 Swift 字典?