Diskuze: Porovnání Listu vlastního datového typu
V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.
Člen
Zobrazeno 14 zpráv z 14.
//= Settings::TRACKING_CODE_B ?> //= Settings::TRACKING_CODE ?>
V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.
Vždyť to funguje... Přepsal sis Equals? Aspoň nějak tahkle?
public override bool Equals(object obj)
{
var clovek = (Clovek)obj;
if (clovek == null)
return false;
return (Jmeno.Equals(clovek.Jmeno) &&
Prijmeni.Equals(clovek.Prijmeni) &&
Vek.Equals(clovek.Vek));
}
Popřípadě můžeš použít komparátor a extension metody:
class MyClass : IEqualityComparer<Clovek>
{
public bool Equals(Clovek x, Clovek y)
{
return (x.Jmeno.Equals(y.Jmeno) &&
x.Prijmeni.Equals(y.Prijmeni) &&
x.Vek.Equals(y.Vek));
}
public int GetHashCode(Clovek obj)
{
return ((obj.Jmeno.GetHashCode() & obj.Prijmeni.GetHashCode()) ^ obj.Vek) * 19;
}
}
foreach (var item in clovek_01.Except(clovek_02, new MyClass()))
{
Console.WriteLine($"{item.Jmeno} {item.Prijmeni}");
}
Já k Honzovi přidám trochu omáčky. To kouzlo je v porovnávání referenčních typů. Ten porovnávací stroj ve výchozím stavu porovnáva odkazy v paměti. Tedy
var clovek_1 = new Clovek()
{
Jmeno = "Marek",
Prijmeni = "Novak",
Vek = 30
}
a toto
var clovek_2 = new Clovek()
{
Jmeno = "Marek",
Prijmeni = "Novak",
Vek = 30
}
Jsou dva různé objekty protože sedí na různých adresách v paměti. Aby to fungovalo jak jsi predpokládal je potřeba tomu porovnávacímu stroji dodat nový "předpis" či "klíč" podle kterého má porovnávat. Honza ti popsal jeden způsob. Kdyby ses kouknul na dokumentaci ke Contains, tak tam to je taktéž popsané.
Ahoj, ještě bych se chtěl zeptat, proč se musí přepisovat GetHashCode() a proč zrovna takto?
return ((obj.Jmeno.GetHashCode() & obj.Prijmeni.GetHashCode()) ^ obj.Vek) * 19;
Díky za případné vysvětlení.
Protože je rychlejší spočítat hash a pak v případě shody ověřit jestli jsou fakt ty objekty shodne.
Tak mi řekni jiný důvod, proč bys měl mít u každého objektu GetHashCode(). Jsem zvědav.
To s tím nesouvisí. Já jenom říkám, že počítání hashe je poměrně náročná činnost oproti porovnání.
Ahoj, ještě dotaz, jak to ošetřím, když bude některá hodnota null (třeba Jmeno nebo Vek) ?
On má svý, způsobem pravdu.. GetHashCode použivají některé kolekce (například dictionary) aby si mohli "pobalíčkovat" objekty a tak zrychlit hledání.
To že je počítání hashe náročné je nesmysl. Vždy záleží na implementaci. Ten hash si můžu klidně dát konstantní a bude to v O(1).
Pokud mám dva objekty které jsou téměř stejné - liší se třeba jen v jedné propertě, budou mít na základě "nepřesné" GetHashCode metody stejnou hodnotu.. POkud tedy tento objekt umístím do Dictionary mezi 1000000 zcela rozdílných objektů a potom se zeptám, jestli se tam nachází "ten druhý" objekt. On si spošte HashCode a pak se koukne u sebe "do přihrádky", kde má jen instanc s tímto HashCodem.. v našem případě je třeba pouze 1.. Nemusí tedy prohledávat více objektů, ale jen mezi těmi co mají stejný HashCode.
Je potřeba číst více slov ... nejenom jedno
Tady je kód pro výpis těch kteří nejsou v kolekci clovek1:
foreach(Clovek clovek in clovek1.Where(s=>clovek2.forEach(b=>b != s)).Select(s=>s))
{
Console.WriteLine(+"jmeno: "+clovek.Jmeno+"\nprijimeni: "+clovek.Prijimeni+"\nvek: "+clovek.Vek);
}
Pokud chceš porovnávat jména stačí udělat toto:
foreach(Clovek clovek in clovek1.Where(s=>clovek2.forEach(b=>b.Jmeno != s.Jmeno)).Select(s=>s))
{
Console.WriteLine(+"jmeno: "+clovek.Jmeno+"\nprijimeni: "+clovek.Prijimeni+"\nvek: "+clovek.Vek);
}
To nadtím je špatně...
foreach (Clovek clovek in clovek1.Where(s=>!clovek2.Contains(s)))
{
Console.WriteLine(+"jmeno: " + clovek.Jmeno + "\nprijimeni: " + clovek.Prijimeni + "\nvek: " + clovek.Vek);
}
A pokud chceš porovnávat třeba jména tak
foreach (Clovek clovek in clovek1.Where(s=>!clovek2.Any(d=>d.Jmeno==s.Jmeno)))
{
Console.WriteLine(+"jmeno: " + clovek.Jmeno + "\nprijimeni: " + clovek.Prijimeni + "\nvek: " + clovek.Vek);
}
Zobrazeno 14 zpráv z 14.