1

プログラムの開始時に、2 つのリスト A と B があり、どちらもデータベースからの情報で満たされています (リスト A = リスト B)。私のプログラムが実行され、リスト A が使用および変更され、リスト B はそのままになります。しばらくして、リスト B にデータベースからの新しい情報を再読み込みし、それをリスト A に対してチェックします。

foreach (CPlayer player in ListA)
      if (ListB.Contains(player))
            -----

まず、クラスからオブジェクト player が作成されます。その主な識別子は player.Name です。Name が同じで、他の変数が異なる場合、.Contains は true を返しますか?

Class CPlayer(
      public CPlayer (string name)
              _Name = name

---- で、.Contains が true を返すようにする ListB のアイテムを使用する必要があります。

4

5 に答える 5

5

のデフォルトの動作List.Containsは、デフォルトの等式比較子を使用することです。アイテムが参照型である場合、これは、クラスがを介して別の実装を提供しない限り、ID比較を使用することを意味しますEquals

.NET 3.5を使用している場合は、2行目をこれに変更して、必要な処理を実行できます。

if (ListB.Any(x => x.Name == player.Name))

.NET 2.0の場合、クラスに対して実装できますEqualsGetHashCode、名前が同じで他のフィールドが異なる2つのプレーヤーオブジェクトを同等に比較したくない他の状況では、これにより望ましくない動作が発生する可能性があります。

別の方法は、JonSkeetの答えを.NET2.0に適合させることです。を作成しDictionary<string, object>、listB内のすべてのプレーヤーの名前を入力します。次に、特定の名前のプレーヤーがlistBにあるかどうかをテストするには、を使用できますdict.ContainsKey(name)

于 2010-04-23T06:06:53.327 に答える
2

Markの提案に代わるものは、名前のセットを作成してそれを使用することです。

HashSet<string> namesB = new HashSet<string>(ListB.Select(x => x.Name));
foreach (CPlayer player in ListA)
{
    if (namesB.Contains(player.Name))
    {
        ...
    }
}
于 2010-04-23T06:12:26.170 に答える
0

これがあなたが達成する必要があることのように聞こえます:

リストAの各プレーヤーについて、リストBで同じ名前の各プレーヤーを見つけ、両方のプレーヤーを同じスコープに入れます。

クエリで2つのリストを結合するアプローチは次のとおりです。

var playerPairs =
    from playerA in ListA
    join playerB in ListB on playerA.Name equals playerB.Name
    select new { playerA, playerB };

foreach(var playerPair in playerPairs)
{
    Console.Write(playerPair.playerA.Name);
    Console.Write(" -> ");
    Console.WriteLine(playerPair.playerB.Name);
}
于 2010-04-23T06:34:38.643 に答える
0

.Contains メソッドを CPlayer.Name でのみ一致させたい場合は、CPlayer クラスでこれらのメソッドを実装します。

public override bool Equals(object obj)
{
    if (!(obj is CPlayer)
        return false;
    return Name == (obj as CPlayer).Name;
}
public override int GetHashCode()
{
    return Name.GetHashCode();
}

比較で大文字と小文字を区別しないようにする場合はName、代わりに次の Equals メソッドを使用します。

public override bool Equals(object obj)
{
    if (!(obj is CPlayer)
        return false;
    return Name.Equals((obj as CPlayer).Name, StringComparison.OrdinalIgnoreCase);
}

これを行うと、.Contains 呼び出しが思いどおりに機能します。次に、リストでこのアイテムを選択する場合は、次のようにします。

var playerB = ListB[ListB.IndexOf(player)];

同じ .Equals および .GetHashCode メソッドを使用します。

UPD: これはおそらく主観的なステートメントですが、文字列比較を行う前に .Equals メソッドが Int ハッシュを比較した場合、パフォーマンスをいくらか引き出すこともできます..

.NET ソース (Reflector FTW) を見ると、.Equals を使用して毎回オブジェクトを比較するのではなく、HastTable クラスだけが GetHashCode を使用してパフォーマンスを改善しているように見えることがわかります。このような小さなクラスの場合、等値比較子は単純で、単一の文字列比較です..ただし、すべてのプロパティを比較していた場合、2 つの整数を比較する方がはるかに高速です (特に、それらがキャッシュされている場合:) )

List.Contains と List.IndexOf はハッシュ コードを使用せず、.Equals メソッドを使用するため、内部のハッシュ コードをチェックすることを提案しました。おそらく目立たないでしょうが、実行のすべてのミリ秒を取得するためにうずうずしている場合(常に良いことではありません、バグねえ! :P )これは誰かを助けるかもしれません. ただ言って... :)

于 2010-04-23T08:39:19.663 に答える
0

クラスを使用していると仮定すると、クラスが実装されていないSystem.Collections.Generic.List場合、クラスのおよび関数を使用して、 の引数に等しいメンバーが にあるかどうかを確認します。実装が問題ないと仮定すると、次のようなことができますCPlayerIEquatable<T>EqualsGetHashCodeCPlayerListContains

CPlayer listBItem = ListB.First(p => p == player);

インスタンスを取得するListB

于 2010-04-23T06:23:12.460 に答える