要素を1つずつステップスルーする以外に、2つの文字列のリストが等しいかどうかを比較する方法(.NET 3.0):
これは失敗します:
// Expected result.
List<string> expected = new List<string>();
expected.Add( "a" );
expected.Add( "b" );
expected.Add( "c" );
// Actual result
actual = new List<string>();
actual.Add( "a" );
actual.Add( "b" );
actual.Add( "c" );
// Verdict
Assert.IsTrue( actual == expected );
以下をお試しください
var equal = expected.SequenceEqual(actual);
テスト版
Assert.IsTrue( actual.SequenceEqual(expected) );
SequenceEqual拡張メソッドは、コレクションの要素が等しいかどうかを比較します。
http://msdn.Microsoft.com/en-us/library/bb348567(v = vs.100).aspx を参照してください
必要な関数自体はいつでも記述できます。
public static bool ListEquals<T>(IList<T> list1, IList<T> list2) {
if (list1.Count != list2.Count)
return false;
for (int i = 0; i < list1.Count; i++)
if (!list1[i].Equals(list2[i]))
return false;
return true;
}
そしてそれを使用します:
// Expected result.
List<string> expected = new List<string>();
expected.Add( "a" );
expected.Add( "b" );
expected.Add( "c" );
// Actual result
actual = new List<string>();
actual.Add( "a" );
actual.Add( "b" );
actual.Add( "c" );
// Verdict
Assert.IsTrue( ListEquals(actual, expected) );
元のコードが機能しなかった理由を実際に誰も話していないことに気付きました。これは、一般テストの==
演算子 参照equality (つまり、2つのインスタンスがメモリ内の同じオブジェクトを指している場合)演算子は オーバーロードされています 。 List<T>
は==
演算子を定義しないため、ベース参照の実装と同等の実装が使用されます。
他のポスターが示したように、一般的に「コレクションの平等」をテストするには要素をステップスルーする必要があります。もちろん、ユーザーが提案した最適化 DreamWalker を使用する必要があります。
順序が重要な場合:
bool equal = a.SequenceEquals(b);
順序が重要でない場合:
bool equal = a.Count == b.Count && new HashSet<string>(a).SetEquals(b);
次のような拡張メソッドを書くことができます。
public static class ListExtensions
{
public static bool IsEqual<T>(this IList<T> list,IList<T> target, IComparer<T> comparer) where T:IComparable<T>
{
if (list.Count != target.Count)
{
return false;
}
int index = 0;
while (index < list.Count &&
comparer.Compare(list[index],target[index]) == 0)
{
index++;
}
if (index != list.Count)
{
return false;
}
return true;
}
}
そして次のように呼び出します:
List<int> intList = new List<int> { 1, 234, 2, 324, 324, 2 };
List<int> targetList = new List<int> { 1, 234, 2, 324, 324 };
bool isEqual = intList.IsEqual(targetList, Comparer<int>.Default);
編集:OPが.NET 3.0を使用しているため、代わりに静的メソッドを使用するようにコードを更新しました
public static bool IsEqual<T>(IList<T> sourceList, IList<T> targetList, IComparer<T> comparer) where T : IComparable<T>
{
if (sourceList.Count != targetList.Count)
{
return false;
}
int index = 0;
while (index < sourceList.Count &&
comparer.Compare(sourceList[index], targetList[index]) == 0)
{
index++;
}
if (index != sourceList.Count)
{
return false;
}
return true;
}
クライアント:
bool isEqual = IsEqual(intList,targetList, Comparer<int>.Default);
Linqを使用して、拡張メソッドとしてコードを記述します。
public static bool EqualsOtherList<T>(this List<T> thisList, List<T> theOtherList)
{
if (thisList == null || theOtherList == null ||
thisList.Count != theOtherList.Count) return false;
return !thisList.Where((t, i) => !t.Equals(theOtherList[i])).Any();
}
コレクションを反復処理しますが、私が作成したこの拡張メソッドは、2つのリストの順序を同じにする必要はなく、Equalsメソッドがオーバーライドされる限り、複雑な型でも機能します。
次の2つのリストはtrueを返します。
List<string> list1 = new List<string>
{
{ "bob" },
{ "sally" },
{ "john" }
};
List<string> list2 = new List<string>
{
{ "sally" },
{ "john" },
{ "bob" }
};
方法:
public static bool IsEqualTo<T>(this IList<T> list1, IList<T> list2)
{
if (list1.Count != list2.Count)
{
return false;
}
List<T> list3 = new List<T>();
foreach (var item in list2)
{
list3.Add(item);
}
foreach (var item in list1)
{
int index = -1;
for (int x = 0; x < list3.Count; x++)
{
if (list3[x].Equals(item))
{
index = x;
}
}
if (index > -1)
{
list3.RemoveAt(index);
}
else
{
return false;
}
}
return !list3.Any();
}
通常の方法ではなく、実装なしでカスタム型にIEquatableで使用される可能性があります
JsonConvert.SerializeObject( myList1) == JsonConvert.SerializeObject( myList2)
しかし、一般的な場合、コメントで言及されているようにSequenceEqualを使用できます https://docs.Microsoft.com/en-us/dotnet/api/system.linq.enumerable.sequenceequal?view=netframework-4.8 =
また、カスタム型のIEquatableインターフェイスを実装することを忘れないでください(文字列型やその他の構造には必要ありません)