1

文字列と辞書を含む文字列配列があります。

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

dict = str_array.toDictionary();

配列をintとStringを使用して辞書に入れるにはどうすればよいですか?これらすべての例をboolで見てきましたが、intとstringが必要です。

int(キー)はディクショナリの実際の位置(dict.count)であり、値はその位置にある配列の値になります。

編集:すべての回答にthxがありますが、配列を反復処理したくありません。array.toDictionaryを使用すると、配列を反復処理して配列の値をディクショナリに割り当てるよりもパフォーマンスが向上すると思います。配列には5k個の要素が含まれる場合があります。

edit2:理由は、辞書をメソッドに渡さなければならないためです...その必須です。そして、私の値はすべて単純な配列内にあります。

edit3:最も重要なことはパフォーマンスです。配列を繰り返し処理してdictに値を割り当てる方が、array.toDictionaryよりも高速かもしれませんが、問題は、両方をベンチマークするための小さなコードがないことです。

4

7 に答える 7

8

forまず、パフォーマンスに関する問題は興味深いものであり、時期尚早の最適化のスマックです。この回答が示すように、ループとのパフォーマンスの数ミリ秒の違いを見ている可能性がありますToDictionary

これをリアルタイムシステムで実行していない限り、私は多くの問題を見ることができません。

ショーに移ります-以下は、辞書を作成するために私が考えることができる3つ(および半分)の異なる方法の大まかなベンチマーク(実際のタイミングのみが信頼できる)です。1つ目はforループを使用し、2つ目は同じことを実行しますが、配列のLengthプロパティは使用しません(目的のため)。3番目と4番目の使用ToDictionary; 1つはaSelectを使用し、もう1つはカウンター変数(ハイブリッド)を使用します。

[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());
}

結果(ビルドをリリースし、Dell 2.4Ghzワークステーションで実行するのに約20秒かかります):

ループ平均の場合:0.28880804ミリ秒

ループ(2)の平均:0.2773845ミリ秒

ToDictionary平均:0.479094339999998ミリ秒

ハイブリッド平均:0.353655779999999ミリ秒

したがって、ループは間違いなく高速です-最も近い実装forの少なくとも22%です。ToDictionary私は100,000の要素でそれを試しました、そしてそれはそれから約30%になります。

2番目のループの結果に注意してください-プロパティをバイパスすることは良い考えであるforことを示唆しているようです。Length確かに私は4回続けて実行しました、そしてこれらは結果です(上からの最初のものを含む):

Forループ: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

ハイブリッド:0.353655779999999、0.3583224、0.352022739999998、0.349865779999999

ただし、少なくとも1つのベンチマーク結果についても結果が反転するのを見てきました。これは、この種のベンチマークがどれほど無意味であるかを示しています。現実的には、キャッシュなどを回避するために、テストごとに異なる配列も生成する必要があります。

別の方法があります。

IDictionary<int, string>呼び出しているメソッドが(注-インターフェース)を受け入れる場合。インターフェースの必要なメンバーを実装する単純なラッパータイプを作成することはできませんDictionary<int, string>。したがって、ディクショナリに投影する必要性を完全に回避できます。特定のメンバーのみが必要な場合に限ります。ほぼ完全な実装は次のとおりです。

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
}
于 2012-07-17T13:11:44.420 に答える
4

これは、配列の単なるインデックスであるキーを使用してディクショナリを作成することが私には意味がない場合でも、必要なことを実行します。

Dictionary<int, string> dict = str_array
    .Select((s, i) => new { S = s, Index = i})
    .ToDictionary(x => x.Index, x => x.S);

配列(またはリスト)のインデクサーは、(少なくとも)辞書キーを検索するのと同じくらい高速です。

https://stackoverflow.com/a/908055/284240

于 2012-07-17T13:13:45.417 に答える
2

単に使用するforeachfor、LINQよりも読みやすくパフォーマンスが優れているので(私は思う)。しかし、この答えは、別の使用方法を提供するためだけのものですEnumerable.ToDictionary:-)

  Dictionary<int, string> dict;
  dict = Enumerable.Range(0, str_array.Length).ToDictionary(i => i, i => str_array[i]);

そして、ここに短いものがあります:

  int i = 0; // start key
  Dictionary<int, string> dict;
  dict = str_array.ToDictionary(s => ++i);
于 2012-07-17T13:26:24.773 に答える
1
foreach(string s in str_array)
    dict.Add(dict.Count, s);

簡単な例として、そのようなものはありますか?

または、次の行に沿って拡張メソッドを定義します。

public static Dictionary<int, T> ToDictionary<T>(this IEnumerable<T> source)
{
    Dictionary<int, T> result = new Dictionary<int, T>();
    foreach(T item in source)
        result.Add(result.Count, item);
}

そして、を呼び出してそれを使用しstr_array.ToDictionary()ます。

于 2012-07-17T13:11:02.680 に答える
1
for (int i = 0; i < str_array.Length; i++)
{
    dict[i] = str_array[i];
}
于 2012-07-17T13:10:17.600 に答える
1

配列はすでにintキーと文字列値を持つ辞書であるかのように考えることができるので、なぜこのようなものが必要になるのかを考えるのは難しいです。

しかし、あなたはこのようにそれを行うことができます:

int i = 0;
foreach (string s in str_array)
{
    dict.Add(i++, s);
}
于 2012-07-17T13:10:31.923 に答える
1

簡単にする場合は、拡張メソッドを使用できます。

public static class ExtensionMethod 
{
    public static IDictionary<int, string> ToDictionary(this string[] array)
    {
        return array
            .Select((k, v) => new { Key = k, Value = v})
            .ToDictionary(x => x.Key, x => x.Value);
    }
}

そして、あなたはそれをあなたのプログラムで使うことができます:

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

dict = str_array.ToDictionary();

パフォーマンスの問題foreach発生している場合にのみ、LinQのパフォーマンスについて心配する必要があることに注意してください。パフォーマンスが異なるのは、巨大な操作だけです。

「ネストされたforeach」と「lambda/linqquery」のパフォーマンス(LINQ-to-Objects)も参照してください。

于 2012-07-17T13:20:46.080 に答える