Zilele acestea mi-a fost pusa urmatoarea intrebare:
Daca va aduceti aminte, in urma cu cateva saptamani am discutat despre CollectionAssert. Aceasta contine o metoda denumita AreEquivalent, care verifica daca doua colectii sunt echivalente. Testul o sa treaca de acest assert daca:
Enjoy!
Intr-un unit test care este cea mai buna modalitate de a compara doua colectii?
Daca va aduceti aminte, in urma cu cateva saptamani am discutat despre CollectionAssert. Aceasta contine o metoda denumita AreEquivalent, care verifica daca doua colectii sunt echivalente. Testul o sa treaca de acest assert daca:
- numarul de elemente este egal
- cele doua colectii contin aceleasi elemente( indiferent de ordinea in care apar)
Dictionary<string,string> collection1=new Dictionary<string, string>();
Dictionary<string, string> collection2 = new Dictionary<string, string>();
...
CollectionAssert.AreEquivalent(collection1,collection2);
In cazul in care avem nevoie in cod sa comparam doua dictionare putem sa face in felul urmator:collection1
.OrderBy(i => i)
.SequenceEqual(collection2.OrderBy(i => i));
Varianta de mai sus este O(n*log(n)). In cazul in care vreti o solutie in O(n), puteti sa incercati o implementare asemanatoare cu aceasta:public class CollectionComparer<T> : IEqualityComparer<IEnumerable<T>>
where T : class
{
public bool Equals(IEnumerable<T> collection1, IEnumerable<T> collection2)
{
if ((collection1 == null && collection2!=null)
|| (collection2 == null && collection1!=null))
{
return false;
}
if (ReferenceEquals(collection1, collection2))
{
return true;
}
int collection1Count = collection1.Count();
if (collection1Count != collection2.Count())
{
return false;
}
return collection1Count == 0
|| !AreCollectinDifferent(collection1, collection2);
}
private static bool AreCollectinDifferent(IEnumerable<T> collection1, IEnumerable<T> collection2)
{
int collection1Count;
int collection2Count;
var firstElementCounts = GetElementCounts(collection1, out collection1Count);
var secondElementCounts = GetElementCounts(collection2, out collection2Count);
if (collection1Count != collection2Count)
{
return true;
}
foreach (KeyValuePair<T,int> keyValuePair in firstElementCounts)
{
collection1Count = keyValuePair.Value;
secondElementCounts.TryGetValue(keyValuePair.Key, out collection2Count);
if (collection1Count != collection2Count)
{
return true;
}
}
return false;
}
private static Dictionary<T, int> GetElementCounts(IEnumerable<T> enumerable,
out int nullCount)
{
var dictionary = new Dictionary<T, int>();
nullCount = 0;
int value;
foreach (T element in enumerable)
{
if (element == null)
{
nullCount++;
continue;
}
dictionary.TryGetValue(element, out value);
dictionary[element] = ++value;
}
return dictionary;
}
public int GetHashCode(IEnumerable<T> enumerable)
{
return enumerable
.OrderBy(x => x)
.Aggregate(
11,
(current, val) => current*13 + val.GetHashCode());
}
}
Enjoy!
11 si 13 ce reprezinta? :)
ReplyDeleteInteresant ca si implementare- altfel, daca timpul m-ar fi presat as fi raspuns la intrebare: foloseste ceva gata facut, precum http://comparenetobjects.codeplex.com/ (l-am folosit in unit teste, si merge brici, exceptand niste situatii destul de particulare)
Am implementat o functie de hash. Ma asteptam ca cineva sa se ia de functie de hash. Nu e cel mai bun algoritm acolo oricum.
ReplyDelete+ o bere Tudor pe cand te intorci :D
Imi dau seama ca e o functie de hash, eram curios de ce 13 si nu.. 15.. :)
ReplyDelete