重複を許さないリストを作るとき、リストを検索して存在しなければ追加するようなプログラムを書く事もあると思う。例えば、

 

List<int> nonDuplicateList

があったときに、

int data

を追加するとして

 

if(!nonDuplicateList.Exists(x => x == data))

    nonDuplicateList.Add(data)

 

のようにしたりとか。

 

データが数件の時には、これでも十分速さは出るものの、データが1000件を超えてくると、めちゃくちゃ遅くなる。毎度走査するから当然と言えば当然。

 

じゃあ高速だしHashを使えばいいじゃん、ということでDictionaryを使うと、今度はValueという要らないデータ領域が発生することになる。必要なデータはKeyであって、Valueはboolだろうとintだろうとなんでもよく、中身がnullであっても処理には関係しない。

 

そこで、System.Collection.Generic.HashSetを使う。ちなみにRubyだとSetとして用意されている。(require 'set'が必要)

 

C#

HashSet<int> set = new HashSet<int>();

 

Ruby

set = Set.new

 

としてやれば、あとは普通のリストと同じように使えば良い。

 

HashSetは集合を管理するクラスなので、重複はない。重複してAddしたところでデータは何も変わらない。なので、検索することなく適当にAddしていけば、勝手に重複のないリストを作り上げてくれる。また、IEnumerableを実装しているので、それ以外は基本的には通常のListと同じように扱えるので、至れり尽くせりである。

 

ただし、データ順序の保証は一切ないので、順序が重要ならば、最後にソートしてやる必要がある。

 

入れた順番とか、値以外の要素によって決まるならDictionaryのValueにでも順序を入れておき、最後にソートして取り出してやるとかしたら速いと思う。この場合だけは、DictionaryのValueが必要な領域となるため、こちらを使うと良いと思う。

ただの覚え書きなので読みやすさとか考えてないです

 

二重起動を防止したいときにMutexを使う。

場所はスタートアップメソッドがいいかと。

 

以下コード

 

using System;

using System.Threading;

 

public static class EntryPoint
{

    private static Mutex _Mutex;

      
    public static void Main()
    {
        try
        {
            if (!GetMutex())
            {
                MessageBox.Show("既に起動しています。");
                return;
            }

 

            //ここにその後の実行コード

 

        }
        finally
        {
            if(_Mutex != null)
                _Mutex.Close();
        }
     }

    private static bool GetMutex()
    {
        if (_Mutex != null)
            return true;

 

        bool isCreated = false;
        try
        {

            //MutexName: Mutexの特定に使う固有名。被らなければ何でもOK

            _Mutex = new Mutex(true, "MutexName", out isCreated);
        }

        //異常終了して解放されなかったときに例外が吐かれていても

        //確保できているので整合性とかの問題がないならtrueでOK。

        catch (AbandonedMutexException)
        {
            isCreated = true;
        }
        return isCreated;
    }
}

 

 

new Mutexをするときに、3引数のものを使うと、同時にMutexを取れたかどうかを最後のoutで指定した変数に入れてくれるので、これを使うと便利。

 

注意点として、たまにReleaseMutexしてからCloseするソースを見かけるが、二重起動を防止する、という意味ではReleaseMutexする意味がない(解放する=アプリ終了)なので、Closeだけで大丈夫(解放もやってくれるから)。むしろ、ReleaseMutexを入れてしまうと、例外を吐いてくる場合があるので、しないほうがいい。

 

参考:MSDN Mutexクラス(System.Threading)  

https://msdn.microsoft.com/ja-jp/library/system.threading.mutex(v=vs.110).aspx