() }, { "Dictionary Search(Sequential)", new List<(long, long, long)>() }, { "OrderedDictionary Search(Contains)", new List<(long, long, long)>() }, { "OrderedDictionary Search(Sequential)", new List<(long, long, long)>() }, { "Dictionary Add(SerialNum)", new List<(long, long, long)>() },// キーに連番を設定 { "Dictionary Add(SerialNum)(initialCapacity)", new List<(long, long, long)>() },// キーに連番を設定, 初期容量を指定 { "Dic"> () }, { "Dictionary Search(Sequential)", new List<(long, long, long)>() }, { "OrderedDictionary Search(Contains)", new List<(long, long, long)>() }, { "OrderedDictionary Search(Sequential)", new List<(long, long, long)>() }, { "Dictionary Add(SerialNum)", new List<(long, long, long)>() },// キーに連番を設定 { "Dictionary Add(SerialNum)(initialCapacity)", new List<(long, long, long)>() },// キーに連番を設定, 初期容量を指定 { "Dic"> () }, { "Dictionary Search(Sequential)", new List<(long, long, long)>() }, { "OrderedDictionary Search(Contains)", new List<(long, long, long)>() }, { "OrderedDictionary Search(Sequential)", new List<(long, long, long)>() }, { "Dictionary Add(SerialNum)", new List<(long, long, long)>() },// キーに連番を設定 { "Dictionary Add(SerialNum)(initialCapacity)", new List<(long, long, long)>() },// キーに連番を設定, 初期容量を指定 { "Dic">
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace CalculatorApp.Backend.Kensyou.HairetsuSokudo
{
    public class HairetsuSokudoHikaku
    {
        // 計測結果の保存用
        private Dictionary<string, List<(long loopCnt, long TimeMs, long MemoryBytes)>> results = new Dictionary<string, List<(long, long, long)>>()
        {
            { "Dictionary Search(Contains)", new List<(long, long, long)>() },
            { "Dictionary Search(Sequential)", new List<(long, long, long)>() },
            { "OrderedDictionary Search(Contains)", new List<(long, long, long)>() },
            { "OrderedDictionary Search(Sequential)", new List<(long, long, long)>() },
            { "Dictionary Add(SerialNum)", new List<(long, long, long)>() },// キーに連番を設定
            { "Dictionary Add(SerialNum)(initialCapacity)", new List<(long, long, long)>() },// キーに連番を設定, 初期容量を指定
            { "Dictionary Add(Random)", new List<(long, long, long)>() },// キーに重複しないランダムな値を設定
            { "Dictionary Add(Random)(initialCapacity)", new List<(long, long, long)>() },// キーに重複しないランダムな値を設定, 初期容量を指定
            { "OrderedDictionary Add(SerialNum)", new List<(long, long, long)>() },// キーに連番を設定
            { "OrderedDictionary Add(SerialNum)(initialCapacity)", new List<(long, long, long)>() },// キーに連番を設定, 初期容量を指定
            { "OrderedDictionary Add(Random)", new List<(long, long, long)>() },// キーに重複しないランダムな値を設定
            { "OrderedDictionary Add(Random)(initialCapacity)", new List<(long, long, long)>() },// キーに重複しないランダムな値を設定, 初期容量を指定
            { "Dictionary Remove", new List<(long, long, long)>() },
            { "OrderedDictionary Remove(PhysicalDeletion)", new List<(long, long, long)>() },// 物理削除
            { "OrderedDictionary Remove(LogicalDeletion)", new List<(long, long, long)>() },// 論理削除
            { "OrderedDictionary Clear", new List<(long, long, long)>() },
        };

        private int loopCnt = 0;
 
        // OrderedDictionary[i]の順序リストの速度検証用
        private Dictionary<string, List<MeasurementResult>> dicOrderedDictionaryAccessList
            = new Dictionary<string, List<MeasurementResult>>()
            {
                {"OrderedDictionary" ,  new List<MeasurementResult>()}
                , {"Dictionary" ,new List<MeasurementResult>()}
            };

        /// <summary>
        /// 速度検証開始
        /// </summary>
        /// <param name="addCount">検証データ量(初期値は10万件)</param>
        /// <param name="numberOfRuns">検証回数(初期値は60回)</param>
        public void KensyouStart(int addCount = 100000, int numberOfRuns = 60)
        {
            try
            {
                System.Diagnostics.Debug.WriteLine("=== 辞書、OrderedDictionaryの速度検証 ===");

                // 重複しないキーの生成
                HashSet<int> uniqueKeys = new HashSet<int>();
                for (int i = 0; i < addCount; i++)
                {
                    uniqueKeys.Add(i);
                }
                int[] keysArray = uniqueKeys.ToArray();  // 配列に変換

                // ランダムキーの生成
                Random random = new Random();
                HashSet<int> uniqueRandomKeys = new HashSet<int>();
                while (uniqueRandomKeys.Count < addCount)
                {
                    uniqueRandomKeys.Add(random.Next());
                }
                int[] keysRandomArray = uniqueRandomKeys.ToArray();  // 配列に変換

                for (loopCnt = 0; loopCnt < numberOfRuns; loopCnt++)
                {
                    // 検索
                    SearchComparison(addCount, keysArray);
                    // 追加
                    AddComparison(addCount, keysArray, keysRandomArray);
                    // 削除
                    RemoveComparison(addCount, keysArray);

                }

                // OrderedDictionary[i]の内部的な線形探索の処理時間を検証(うまくいかなかった)
                //MeasureOrderedDictionaryAccessProc();

                // 結果出力
                PrintResults();
            }
            catch (Exception ex)
            {
                LogError(ex, nameof(KensyouStart));
                throw;
            }
           
        }

        /// <summary>
        /// 検索処理検証
        /// </summary>
        /// <param name="addCount"></param>
        /// <param name="keysArray"></param>
        private void SearchComparison(int addCount, int[] keysArray)
        {
            try
            {
                int searchCount = keysArray.Length;  // 10万回検索を行う

                // 検索に使用するデータ
                var orderedDictionary = new OrderedDictionary<int, int>();
                foreach (int key in keysArray)
                {
                    orderedDictionary.Add(key, key);
                }

                // 辞書(Contains)
                Dictionary<int, int> dictionary = keysArray.ToDictionary(x => x, x => x);
                MeasureTimeAndMemory("Dictionary Search(Contains)", () =>
                {
                    for (int i = 0; i < searchCount; i++)
                    {
                        bool found = dictionary.ContainsKey(i);
                    }
                });

                // 辞書(Sequential)
                MeasureTimeAndMemory("Dictionary Search(Sequential)", () =>
                {
                    for (int i = 0; i < searchCount; i++)
                    {
                        var item = dictionary[i];
                    }
                });

                // OrderedDictionary(Contains)
                MeasureTimeAndMemory("OrderedDictionary Search(Contains)", () =>
                {
                    for (int i = 0; i < searchCount; i++)
                    {
                        bool found = orderedDictionary.ContainsKey(i);
                    }
                });

                // OrderedDictionary(Sequential)
                MeasureTimeAndMemory("OrderedDictionary Search(Sequential)", () =>
                {
                    for (int i = 0; i < searchCount; i++)  // 順番通りに検索
                    {
                        var item = orderedDictionary[i];
                    }
                });
            }
            catch (Exception ex)
            {
                LogError(ex, nameof(SearchComparison));
                throw;
            }
            
        }

        /// <summary>
        /// 追加処理検証
        /// </summary>
        /// <param name="addCount"></param>
        /// <param name="keysArray"></param>
        private void AddComparison(int addCount, int[] keysArray, int[] keysRandomArray)
        {
            try
            {
                // 辞書(SerialNum)
                Dictionary<int, string> dictionary = new Dictionary<int, string>();
                MeasureTimeAndMemory("Dictionary Add(SerialNum)", () =>
                {
                    for (int i = 0; i < addCount; i++)
                    {
                        dictionary.Add(i, $"Value_{i}");
                    }
                });

                // 辞書(SerialNum)(initialCapacity) 初期容量を指定
                Dictionary<int, string> dictionaryInitialCapacity = new Dictionary<int, string>(addCount);
                MeasureTimeAndMemory("Dictionary Add(SerialNum)(initialCapacity)", () =>
                {
                    for (int i = 0; i < addCount; i++)
                    {
                        dictionaryInitialCapacity.Add(i, $"Value_{i}");
                    }
                });

                // 辞書(Random)
                Dictionary<int, string> dictionaryRandom = new Dictionary<int, string>();
                MeasureTimeAndMemory("Dictionary Add(Random)", () =>
                {
                    for (int i = 0; i < addCount; i++)
                    {
                        dictionaryRandom.Add(keysRandomArray[i], $"Value_{i}");
                    }
                });

                // 辞書(Random)(initialCapacity) 初期容量を指定
                Dictionary<int, string> dictionaryRandomInitialCapacity = new Dictionary<int, string>(addCount);
                MeasureTimeAndMemory("Dictionary Add(Random)(initialCapacity)", () =>
                {
                    for (int i = 0; i < addCount; i++)
                    {
                        dictionaryRandomInitialCapacity.Add(keysRandomArray[i], $"Value_{i}");
                    }
                });

                // OrderedDictionary(SerialNum)
                var orderedDictionarySequential = new OrderedDictionary<int, string>();
                MeasureTimeAndMemory("OrderedDictionary Add(SerialNum)", () =>
                {
                    for (int i = 0; i < addCount; i++)
                    {
                        orderedDictionarySequential.Add(i, $"Value_{i}");
                    }
                });

                // OrderedDictionary(SerialNum)(initialCapacity) 初期容量を指定
                var orderedDictionaryInitialCapacity = new OrderedDictionary<int, string>(addCount);
                MeasureTimeAndMemory("OrderedDictionary Add(SerialNum)(initialCapacity)", () =>
                {
                    for (int i = 0; i < addCount; i++)
                    {
                        orderedDictionaryInitialCapacity.Add(keysArray[i], $"Value_{keysArray[i]}");
                    }
                });

                // OrderedDictionary(Random)
                var orderedDictionaryRandom = new OrderedDictionary<int, string>();
                MeasureTimeAndMemory("OrderedDictionary Add(Random)", () =>
                {
                    for (int i = 0; i < addCount; i++)
                    {
                        orderedDictionaryRandom.Add(keysRandomArray[i], $"Value_{i}");
                    }
                });

                // OrderedDictionary(Random)(initialCapacity) 初期容量を指定
                var orderedDictionaryRandomInitialCapacity = new OrderedDictionary<int, string>(addCount);
                MeasureTimeAndMemory("OrderedDictionary Add(Random)(initialCapacity)", () =>
                {
                    for (int i = 0; i < addCount; i++)
                    {
                        orderedDictionaryRandomInitialCapacity.Add(keysRandomArray[i], $"Value_{i}");
                    }
                });
            }
            catch (Exception ex)
            {
                LogError(ex, nameof(AddComparison));
                throw;
            }
        }

        /// <summary>
        /// 削除処理検証
        /// </summary>
        /// <param name="addCount"></param>
        /// <param name="keysArray"></param>
        private void RemoveComparison(int addCount, int[] keysArray)
        {
            try
            {
                int removeCount = keysArray.Length;
                Random random = new Random();

                // 辞書
                Dictionary<int, int> dictionary = keysArray.Take(removeCount).ToDictionary(x => x, x => x);
                MeasureTimeAndMemory("Dictionary Remove", () =>
                {
                    for (int i = 0; i < removeCount; i++)
                    {
                        int valueToSearch = random.Next(0, removeCount - i);
                        dictionary.Remove(valueToSearch);
                    }
                });

                // OrderedDictionary(PhysicalDeletion)物理削除
                var orderedDictionaryPhysicalDeletion = new OrderedDictionary<int, string>();
                foreach (int key in keysArray.Take(removeCount))
                {
                    orderedDictionaryPhysicalDeletion.Add(key, $"Value_{key}");
                }
                MeasureTimeAndMemory("OrderedDictionary Remove(PhysicalDeletion)", () =>
                {
                    for (int i = 0; i < removeCount; i++)
                    {
                        orderedDictionaryPhysicalDeletion.Remove(0);
                    }
                });

                // OrderedDictionary(LogicalDeletion)論理削除
                var orderedDictionaryLogicalDeletion = new OrderedDictionary<int, ItemStatus>();
                foreach (int key in keysArray)
                {
                    orderedDictionaryLogicalDeletion.Add(key, new ItemStatus { Value = $"Value_{key}", IsDeleted = false });
                }
                MeasureTimeAndMemory("OrderedDictionary Remove(LogicalDeletion)", () =>
                {
                    for (int i = 0; i < removeCount; i++)
                    {
                        orderedDictionaryLogicalDeletion[i].IsDeleted = true;  // フラグを直接変更
                    }
                });

                // OrderedDictionary(Clear)
                var orderedDictionaryClear = new OrderedDictionary<int, string>();
                foreach (int key in keysArray.Take(removeCount))
                {
                    orderedDictionaryClear.Add(key, $"Value_{key}");
                }
                MeasureTimeAndMemory("OrderedDictionary Clear", () =>
                {
                    orderedDictionaryClear.Clear();
                });
            }
            catch (Exception ex)
            {
                LogError(ex, nameof(RemoveComparison));
                throw;
            }
            
        }

        /// <summary>
        /// OrderedDictionary[i]の内部的な線形探索の処理時間を検証(うまくいかなかった)
        /// </summary>
        /// <param name="addCount"></param>
        private void MeasureOrderedDictionaryAccessProc(int addCount = 10000000)
        {
            try
            {
                // 事前準備: 重複しないキーを事前生成し、配列に変換
                HashSet<int> uniqueKeys = new HashSet<int>();
                for (int i = 0; i < addCount; i++)
                {
                    uniqueKeys.Add(i);
                }
                int[] keysArray = uniqueKeys.ToArray();  // 配列に変換

                // 検索に使用するデータ
                var orderedDictionary = new OrderedDictionary<int, int>();
                foreach (int key in keysArray)
                {
                    orderedDictionary.Add(key, key);
                }

                int step = 10000;  // 計測間隔
                var results = new List<MeasurementResult>();

                for (int i = 0; i < addCount; i += step)
                {
                    var stopwatch = new Stopwatch();
                    stopwatch.Start();

                    // 1回の計測で10000回繰り返しアクセス
                    for (int j = 0; j < step; j++)
                    {
                        var value = orderedDictionary[i + j];
                    }

                    stopwatch.Stop();
                    double totalElapsedTimeMs = stopwatch.Elapsed.TotalMilliseconds;  // 合計時間
                    double averageTimePerAccess = totalElapsedTimeMs / step;  // 1回あたりの平均時間

                    results.Add(new MeasurementResult() { Count = i.ToString(), AverageTimeMs = averageTimePerAccess.ToString("F10") });
                }

                dicOrderedDictionaryAccessList["OrderedDictionary"]
                    .AddRange(results);
            }
            catch (Exception ex)
            {
                LogError(ex, nameof(MeasureOrderedDictionaryAccessProc));
                throw;
            }
        }

        /// <summary>
        /// 処理の開始、および速度測定とメモリ使用量測定
        /// </summary>
        /// <param name="operationName"></param>
        /// <param name="action"></param>
        private void MeasureTimeAndMemory(string operationName, Action action)
        {
            try
            {
                var stopwatch = new Stopwatch();
                long beforeMemory = GC.GetTotalMemory(true);  // 実行前のメモリ使用量を取得

                stopwatch.Start();
                action();
                stopwatch.Stop();

                long afterMemory = GC.GetTotalMemory(false);  // 実行後のメモリ使用量を取得
                var result = ((long)loopCnt, stopwatch.ElapsedMilliseconds, afterMemory - beforeMemory);
                results[operationName].Add(result);
            }
            catch (Exception ex)
            {
                LogError(ex, nameof(MeasureTimeAndMemory));
                throw;
            }
        }

        /// <summary>
        /// 測定結果出力
        /// </summary>
        private void PrintResults()
        {
            try
            {

                System.Diagnostics.Debug.WriteLine($"各配列やコレクションの平均(初回処理は集計から除外)");
                System.Diagnostics.Debug.WriteLine($"名前\\t平均時間 ms\\t平均メモリ使用量 KB");
                foreach (var entry in results)
                {
                    if (entry.Value.Count > 1)
                    {
                        entry.Value.RemoveAt(0);// 初回は除外
                    }
                    string name = entry.Key;
                    var times = entry.Value.Select(x => x.TimeMs).ToArray();
                    var memories = entry.Value.Select(x => x.MemoryBytes).ToArray();

                    long avgTime = (long)times.Average();
                    double avgMemory = memories.Average(); 

                    System.Diagnostics.Debug.WriteLine($"{name}\\t{avgTime} ms\\t\\t{avgMemory:F1} BYTE");

                }

                //  OrderedDictionary[i]の内部的な線形探索の処理時間検証結果出力
                foreach (var entry in dicOrderedDictionaryAccessList)
                {
                    string fileName = $"{entry.Key}_{DateTime.Now:yyyyMMdd_HHmmss}.csv";
                    string downloadsFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Downloads");
                    string fullPath = Path.Combine(downloadsFolder, fileName);
                    if (!Directory.Exists(downloadsFolder))
                    {
                        Directory.CreateDirectory(downloadsFolder);
                    }

                    using (var writer = new StreamWriter(fullPath))
                    {
                        writer.WriteLine("Count,AverageTime(ms)");
                        foreach (var item in entry.Value)
                        {
                            writer.WriteLine($"{item.Count},{item.AverageTimeMs:F4}");
                        }

                    }

                }
            }
            catch (Exception ex)
            {
                LogError(ex, nameof(PrintResults));
                throw;
            }
        }
        /// <summary>
        /// エラーログ出力メソッド
        /// </summary>
        /// <param name="ex"></param>
        /// <param name="methodName"></param>
        private void LogError(Exception ex, string methodName)
        {
            System.Diagnostics.Debug.WriteLine($"[Error in {methodName}] {ex.Message}");
        }

    }

    /// <summary>
    /// 論理削除フラグを持つクラス
    /// </summary>
    public class ItemStatus
    {
        public string Value { get; set; }  // 値
        public bool IsDeleted { get; set; }  // 論理削除フラグ
    }

    /// <summary>
    /// シーケンシャルアクセス検証用
    /// </summary>
    public class MeasurementResult
    {
        public string Count { get; set; }
        public string AverageTimeMs { get; set; }
    }

}