c# - Overloading Linq Except to allow custom struct with byte array -
i having problem custom struct , overloading linq's except method remove duplicates.
my struct follows:
public struct hashedfile { string _filestring; byte[] _filehash; public hashedfile(string filestring, byte[] filehash) { this._filestring = filestring; this._filehash = filehash; } public string filestring { { return _filestring; } } public byte[] filehash { { return _filehash; } } }
now, following code works fine:
public static void test2() { list<hashedfile> list1 = new list<hashedfile>(); list<hashedfile> list2 = new list<hashedfile>(); hashedfile 1 = new hashedfile("test1", bitconverter.getbytes(1)); hashedfile 2 = new hashedfile("test2", bitconverter.getbytes(2)); hashedfile 3 = new hashedfile("test3", bitconverter.getbytes(3)); hashedfile threea = new hashedfile("test3", bitconverter.getbytes(4)); hashedfile 4 = new hashedfile("test4", bitconverter.getbytes(4)); list1.add(one); list1.add(two); list1.add(threea); list1.add(four); list2.add(one); list2.add(two); list2.add(three); list<hashedfile> diff = list1.except(list2).tolist(); foreach (hashedfile h in diff) { messagebox.show(h.filestring + environment.newline + h.filehash[0].tostring("x2")); } }
this code shows "threea" , "four" fine. if following.
public static list<hashedfile> list1(var stuff1) { //generate list here , return } public static list<hashedfile> list2(var stuff2) { //generate list here , return } list<hashedfile> diff = list1.except(list2);
"diff" becomes exact copy of "list1". should mention sending byte array computehash system.security.cryptography.md5 byte filehash in list generations.
any ideas on how overload either except or gethashcode method linq exclude duplicate values list2?
i'd appreciate it! thanks! ~mrfreeman
edit: here how trying use list<hashedfile> diff = newlist.except(oldlist, new hashedfilecomparer()).tolist();
class hashedfilecomparer : iequalitycomparer<hashedfile> { public bool equals(hashedfile x, hashedfile y) { if (object.referenceequals(x, y)) return true; if (object.referenceequals(x, null) || object.referenceequals(y, null)) return false; return x.filestring == y.filestring && x.filehash == y.filehash; } public int gethashcode(hashedfile hashedfile) { if (object.referenceequals(hashedfile, null)) return 0; int hashfilestring = hashedfile.filestring == null ? 0 : hashedfile.filestring.gethashcode(); int hashfilehash = hashedfile.filehash.gethashcode(); int returnval = hashfilestring ^ hashfilehash; if (hashedfile.filestring.contains("blankmusic") == true) { console.writeline(returnval.tostring()); } return returnval; } }
if want type handle own comparisons in except interface need iequatable. iequalitycomparer interface have type handle comparisons can passed except overload.
this achieves want (assuming wanted both file string , hash compared).
public struct hashedfile : iequatable<hashedfile> { string _filestring; byte[] _filehash; public hashedfile(string filestring, byte[] filehash) { this._filestring = filestring; this._filehash = filehash; } public string filestring { { return _filestring; } } public byte[] filehash { { return _filehash; } } public bool equals(hashedfile other) { return _filestring == other._filestring && _filehash.sequenceequal(other._filehash); } }
here example in working console application.
public class program { public struct hashedfile : iequatable<hashedfile> { string _filestring; byte[] _filehash; public hashedfile(string filestring, byte[] filehash) { this._filestring = filestring; this._filehash = filehash; } public string filestring { { return _filestring; } } public byte[] filehash { { return _filehash; } } public bool equals(hashedfile other) { return _filestring == other._filestring && _filehash.sequenceequal(other._filehash); } } public static void main(string[] args) { list<hashedfile> list1 = getlist1(); list<hashedfile> list2 = getlist2(); list<hashedfile> diff = list1.except(list2).tolist(); foreach (hashedfile h in diff) { console.writeline(h.filestring + environment.newline + h.filehash[0].tostring("x2")); } console.readline(); } private static list<hashedfile> getlist1() { hashedfile 1 = new hashedfile("test1", bitconverter.getbytes(1)); hashedfile 2 = new hashedfile("test2", bitconverter.getbytes(2)); hashedfile threea = new hashedfile("test3", bitconverter.getbytes(4)); hashedfile 4 = new hashedfile("test4", bitconverter.getbytes(4)); var list1 = new list<hashedfile>(); list1.add(one); list1.add(two); list1.add(threea); list1.add(four); return list1; } private static list<hashedfile> getlist2() { hashedfile 1 = new hashedfile("test1", bitconverter.getbytes(1)); hashedfile 2 = new hashedfile("test2", bitconverter.getbytes(2)); hashedfile 3 = new hashedfile("test3", bitconverter.getbytes(3)); var list1 = new list<hashedfile>(); list1.add(one); list1.add(two); list1.add(three); return list1; } }
this becoming quite large continue there issue above implementation if hashedfile class not struct (and when stuct maybe version depdendant). except uses internal set class relevant part of problematic compares hash codes , if equal use comparer check equality.
int hashcode = this.internalgethashcode(value); (int = this.buckets[hashcode % this.buckets.length] - 1; >= 0; = this.slots[i].next) { if ((this.slots[i].hashcode == hashcode) && this.comparer.equals(this.slots[i].value, value)) { return true; } }
the fix depending on performance requirements can return 0 hash code. means comparer used.
public override int gethashcode() { return 0; }
the other option generate proper hash code matters sooner expected difference 500 items 7ms vs 1ms , 5000 items 650ms vs 13ms. best go proper hash code. byte array hash code function taken https://stackoverflow.com/a/7244316/1002621
public override int gethashcode() { var hashcode = 0; var bytes = _filehash.union(encoding.utf8.getbytes(_filestring)).toarray(); (var = 0; < bytes.length; i++) hashcode = (hashcode << 3) | (hashcode >> (29)) ^ bytes[i]; // rotate 3 bits , xor new value. return hashcode; }
Comments
Post a Comment