I have added the following property to my ApplicationUser class, which is supposed to return current user on top of other results.
public static IComparer<string> IdComparer
{
get
{
return Comparer<string>.Create((x, y) =>
{
var curUser = HttpContext.Current.User;
if (curUser != null)
{
var curId = curUser.Identity.GetUserId();
if (x == curId)
return -1;
else if (y == curId)
return 1;
}
return string.Compare(x, y);
});
}
}
Anyway, does generating a comparer cost more than storing it? Should I add a static field and return a singleton for this property?
I'm thinking about returning the same comparer:
private static object sync = new object();
private static IComparer<string> _IdComparer;
public static IComparer<string> IdComparer
{
get
{
if (_IdComparer == null)
lock (sync)
if (_IdComparer == null)
_IdComparer = Comparer<string>.Create((x, y) =>
{
var curUser = HttpContext.Current.User;
if (curUser != null)
{
var curId = curUser.Identity.GetUserId();
if (x == curId)
return -1;
else if (y == curId)
return 1;
}
return string.Compare(x, y);
});
return _IdComparer;
}
}
Is this safe? Any corrections or enhancements?
Generating the comparer definitely costs more than storing it. It's a heap allocation, and more than one (you have to allocate the auto-generated class for the lambda).
You probably shouldn't worry about it though. The overhead is very small.
Your edit is fine. You don't even need to use a lock or checking for null. The assignment operation is guaranteed to be atomic. In the worst case you just create the same comparer twice.
By initializer below I mean:
static readonly IComparer<string> _IdComparer = Comparer<string>.Create((x, y) => {
var curUser = HttpContext.Current.User;
if (curUser != null) {
var curId = curUser.Identity.GetUserId();
if (x == curId)
return -1;
else if (y == curId)
return 1;
}
return string.Compare(x, y);
});
public static IComparer<string> IdComparer {
get {
return _IdComparer;
}
}
I don't really understand how you can be unaware of the initializer.
Related
I want an alphabetic sort with one exception.
There is a Group with a Name = "Public" and an ID = "0" that I want first.
(would rather use ID = 0)
After that then sort the rest by Name.
This does not return public first.
public IEnumerable<GroupAuthority> GroupAuthoritysSorted
{
get
{
return GroupAuthoritys.OrderBy(x => x.Group.Name);
}
}
What I want is:
return GroupAuthoritys.Where(x => x.ID == 0)
UNION
GroupAuthoritys.Where(x => x.ID > 0).OrderBy(x => x.Group.Name);
GroupAuthority has a public property Group and Group has Public properties ID and Name.
I used basically the accepted answer
using System.ComponentModel;
namespace SortCustom
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
TestSort();
}
private void TestSort()
{
List<CustomSort> LCS = new List<CustomSort>();
LCS.Add(new CustomSort(5, "sss"));
LCS.Add(new CustomSort(6, "xxx"));
LCS.Add(new CustomSort(4, "xxx"));
LCS.Add(new CustomSort(3, "aaa"));
LCS.Add(new CustomSort(7, "bbb"));
LCS.Add(new CustomSort(0, "pub"));
LCS.Add(new CustomSort(2, "eee"));
LCS.Add(new CustomSort(3, "www"));
foreach (CustomSort cs in LCS) System.Diagnostics.Debug.WriteLine(cs.Name);
LCS.Sort();
foreach (CustomSort cs in LCS) System.Diagnostics.Debug.WriteLine(cs.Name);
}
}
public class CustomSort : Object, INotifyPropertyChanged, IComparable<CustomSort>
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null) PropertyChanged(this, e);
}
private Int16 id;
private string name;
public Int16 ID { get { return id; } }
public String Name { get { return name; } }
public int CompareTo(CustomSort obj)
{
if (this.ID == 0) return -1;
if (obj == null) return 1;
if (obj is CustomSort)
{
CustomSort comp = (CustomSort)obj;
if (comp.ID == 0) return 1;
return string.Compare(this.Name, comp.Name, true);
}
else
{
return 1;
}
}
public override bool Equals(Object obj)
{
// Check for null values and compare run-time types.
if (obj == null) return false;
if (!(obj is CustomSort)) return false;
CustomSort comp = (CustomSort)obj;
return (comp.ID == this.ID);
}
public override int GetHashCode()
{
return (Int32)ID;
}
public CustomSort(Int16 ID, String Name)
{
id = ID;
name = Name;
}
}
}
You need to use a comparison function, they are functions that from two instances of your type return an integer that return 0 if both are equals, a negative value if the first is less than the second and a positive value if the first is greater than the second.
MSDN has a nice table that is easier to follow than text (StackOverflow still doesn't support tables in 2014)
IComparer<T>
Most sort methods accept a custom comparer implementation of type IComparer<T> you should create one encapsulating your custom rules for Group :
class GroupComparer : IComparer<Group>
{
public int Compare(Group a, Group b)
{
if (a != null && b != null && (a.Id == 0 || b.Id == 0))
{
if (a.Id == b.Id)
{
// Mandatory as some sort algorithms require Compare(a, b) and Compare(b, a) to be consistent
return 0;
}
return a.Id == 0 ? -1 : 1;
}
if (a == null || b == null)
{
if (ReferenceEquals(a, b))
{
return 0;
}
return a == null ? -1 : 1;
}
return Comparer<string>.Default.Compare(a.Name, b.Name);
}
}
Usage:
items.OrderBy(_ => _, new GroupAuthorityComparer());
IComparable<T>
If it is the only way to compare Group instances you should make it implement IComparable<T> so that no aditional code is needed if anyone want to sort your class :
class Group : IComparable<Group>
{
...
public int CompareTo(Group b)
{
if (b != null && (Id == 0 || b.Id == 0))
{
if (Id == b.Id)
{
// Mandatory as some sort algorithms require Compare(a, b) and Compare(b, a) to be consistent
return 0;
}
return Id == 0 ? -1 : 1;
}
return Comparer<string>.Default.Compare(Name, b.Name);
}
}
Usage:
items.OrderBy(_ => _.Group);
The choice between one way or the other should be done depending on where this specific comparer is used: Is it the main ordering for this type of item or just the ordering that should be used in one specific case, for example only in some administrative view.
You can even go one level up and provide an IComparable<GroupAuthority> implementation (It's easy once Group implement IComparable<Group>):
class GroupAuthority : IComparable<GroupAuthority>
{
...
public int CompareTo(GroupAuthority b)
{
return Comparer<Group>.Default.Compare(Group, b.Group);
}
}
Usage:
items.OrderBy(_ => _);
The advantage of the last one is that it will be used automatically, so code like: GroupAuthoritys.ToList().Sort() will do the correct thing out of the box.
You can try something like this
list.Sort((x, y) =>
{
if (x.Id == 0)
{
return -1;
}
if (y.Id == 0)
{
return 1;
}
return x.Group.Name.CompareTo(y.Group.Name);
});
Where list is List<T>.
This method takes advantage of custom sort option provided by List<T> using Comparison<T> delegate.
Basically what this method does is, it just adds special condition for comparison when Id, If it is zero it will return a value indicating the object is smaller which makes the object to come in top of the list. If not, it sorts the object using its Group.Name property in ascending order.
public IEnumerable<GroupAuthority> GroupAuthoritysSorted
{
get
{
return GroupAuthoritys.OrderBy(x => x.Group.ID == 0)
.ThenBy(x => x.Group.Name);
}
}
I have problem with CustomType in Fluent NHibernate.
I have to save as Json a dictionary to my database.
I created a customType for this that implements IUserType interface.
There is no problem to save dictionary to database for first time, but when i try to update collection, nHibernate dont set a property as dirty and dont update it.
My Equals and GetHashCode methods
public new bool Equals(object x, object y)
{
if (x == null && y == null)
return true;
if (x == null || y == null)
return false;
if (!(x is IDictionary<K, Z>) || !(y is IDictionary<K, Z>))
return false;
var dic1 = (x as IDictionary<K, Z>).OrderBy(z=> z.Key);
var dic2 = (y as IDictionary<K, Z>).OrderBy(z => z.Key);
return dic1.SequenceEqual(dic2);
}
public int GetHashCode(object x)
{
if (x == null)
return 0;
return x.GetHashCode();
}
The objects passed to equals method are always the same (recently modified) two object.
Anyone have a idea what i'm doing wrong ?
Rest of IUserType implementation code:
public object NullSafeGet(IDataReader rs, string[] names, object owner)
{
if (names.Length != 1)
throw new InvalidOperationException("Only expecting one column...");
var val = rs[names[0]] as string;
if (val != null && !string.IsNullOrWhiteSpace(val))
{
return JsonConvert.DeserializeObject<T>(val, JSonSerializableTypeSerializer.Settings);
}
return null;
}
public void NullSafeSet(IDbCommand cmd, object value, int index)
{
var parameter = (DbParameter)cmd.Parameters[index];
if (value == null)
{
parameter.Value = DBNull.Value;
}
else
{
parameter.Value = JsonConvert.SerializeObject(value, JSonSerializableTypeSerializer.Settings);
}
}
public object DeepCopy(object value)
{
return value;
}
public object Replace(object original, object target, object owner)
{
return original;
}
public object Assemble(object cached, object owner)
{
return cached;
}
public object Disassemble(object value)
{
return value;
}
public SqlType[] SqlTypes
{
get
{
return new SqlType[] { new StringClobSqlType() };
}
}
public Type ReturnedType
{
get { return typeof(T); }
}
public bool IsMutable
{
get { return true; }
}
Maybe I am wrong, but I guess you have returned false while implementing IUserType.IsMutable.
Since your user type returns a Dictionary, which is a mutable type, and which you do indeed mutate, your user type must return true for its IsMutable property.
I'm not really sure, why grouping by IEnumerable<string> does not work. I provide custom IEqualityComparer, of course.
public class StringCollectionEqualityComparer : EqualityComparer<IEnumerable<string>>
{
public override bool Equals(IEnumerable<string> x, IEnumerable<string> y)
{
if (Object.Equals(x, y) == true)
return true;
if (x == null) return y == null;
if (y == null) return x == null;
return x.SequenceEqual(y, StringComparer.OrdinalIgnoreCase);
}
public override int GetHashCode(IEnumerable<string> obj)
{
return obj.OrderBy(value => value, StringComparer.OrdinalIgnoreCase).Aggregate(0, (hashCode, value) => value == null ? hashCode : hashCode ^ value.GetHashCode() + 33);
}
}
class A
{
public IEnumerable<string> StringCollection { get; set; }
}
IEnumerable<A> collection = // collection of A
var grouping = collection.GroupBy(obj => a.StringCollection, StringCollectionEqualityComparer.Default).ToList();
(ToList() is to force evaluation, I have breakpoints in StringCollectionEqualityComparer, but unfortunately, they're not invoked, as expected)
When I group collection in this dumb way, it actually works.
var grouping = collection.GroupBy(obj => String.Join("|", obj.StringCollection));
Unfortunately, obviously it is not something I want to use.
By not working, I mean the results are not the ones I expect (using dumb way, the results are correct).
StringCollectionEqualityComparer.Default is a valid alternative way to access EqualityComparer<IEnumerable<string>>.Default, since the latter is a base class of the former. You need to create an instance of StringCollectionEqualityComparer, simply using new StringCollectionEqualityComparer(), instead.
I'm having two lists were one of the lists InboxTemp is automatically is filled with all the objects that exists. The other list NewMessages is randomly (10-60sec) recieving new objects. The problem I have is that I want allList to add the objects in newList without any duplicates.
public List<object> GetNewMessages()
{
if (NewMessages.Count > 0 && InboxTemp.Count > 0)
{
for (int j = 0; j < NewMessages.Count; j++)
{
for (int i = 0; i < InboxTemp.Count; i++)
{
if (InboxTemp[i].ID != NewMessages[j].ID)
{
InboxTemp.Add(NewMessages[j]);
}
}
}
}
NewMessages.Clear();
return InboxTemp;
}
The problem here is that we get duplicates, I just want the new objects to addup with the InboxTemp-list .
var newItems = NewMessages.Where(x => !InboxTemp.Any(z => z.ID == x.ID));
InboxTemp.AddRange(newItems);
If it is possible, please create class implementing IEqualityComparer to compare objects id.
class MyEqualityComparerer : IEqualityComparer<MyMessage>
{
public bool Equals(MyMessage x, MyMessage y)
{
if (x == null && y == null)
{
return true;
}
if (x == null)
{
return false;
}
if (y == null)
{
return false;
}
return x.Id == y.Id;
}
public int GetHashCode(MyMessage obj)
{
if(obj == null)
{
return 0;
}
return obj.Id.GetHashCode();
}
}
Then write get Distinct values from messages and add all not present in the old list to it
var newItems = newList.Distinct(new MyEqualityComparerer()).Except(oldList, new MyEqualityComparerer()).ToList();
oldList.AddRange(newItems);
You could use the modified code based on what you posted:
public List<object> GetNewMessages()
{
if (NewMessages.Count > 0 && InboxTemp.Count > 0)
{
for (int j = 0; j < NewMessages.Count; j++)
{
bool found = false;
int i = 0;
while(!found && i<InboxTemp.Count)
{
if (InboxTemp[i].ID == NewMessages[j].ID)
{
found = true;
}
j++;
}
if(!found)
InboxTemp.Add(NewMessages[j]);
}
}
NewMessages.Clear();
return InboxTemp;
}
Use except:
InboxTemp = InboxTemp.Except(NewMessages);
From MSDN:
Produces the set difference of two sequences by using the default equality comparer to compare values....
...The default equality comparer, Default, is used to compare values of
the types that implement the IEqualityComparer(Of T) generic
interface. To compare a custom data type, you need to implement this
interface and provide your own GetHashCode and Equals methods for the
type.
Source: MSDN Except
You can use Enumerable.Except to find all new messages.
public List<Msg> GetNewMessages()
{
var newMsg = NewMessages.Except(InboxTemp, new MsgComparer()).ToList();
foreach(var msg in newMsg)
InboxTemp.Add(msg);
return newMsg;
}
But you need to create a custom IEqualityComparer<T> for your object (i'll call it Msg):
public class MsgComparer: IEqualityComparer<Msg>
{
public bool Equals(Msg x1, Msg x2)
{
if (object.ReferenceEquals(x1, x2))
return true;
if (x1 == null || x2 == null)
return false;
return x1.ID.Equals(x2.ID);
}
public int GetHashCode(Msg obj)
{
return obj.ID.GetHashCode();
}
}
There are many ways to do this but I feel like I've missed a function or something.
Obviously List == List will use Object.Equals() and return false.
If every element of the list is equal and present in the same location in the opposite list then I would consider them to be equal. I'm using value types, but a correctly implemented Data object should work in the same fashion (i.e I'm not looking for a shallow copied list, only that the value of each object within is the same).
I've tried searching and there are similar questions, but my question is an equality of every element, in an exact order.
Enumerable.SequenceEqual<TSource>
MSDN
Evil implementation is
if (List1.Count == List2.Count)
{
for(int i = 0; i < List1.Count; i++)
{
if(List1[i] != List2[i])
{
return false;
}
}
return true;
}
return false;
I put together this variation:
private bool AreEqual<T>(List<T> x, List<T> y)
{
// same list or both are null
if (x == y)
{
return true;
}
// one is null (but not the other)
if (x== null || y == null)
{
return false;
}
// count differs; they are not equal
if (x.Count != y.Count)
{
return false;
}
for (int i = 0; i < x.Count; i++)
{
if (!x[i].Equals(y[i]))
{
return false;
}
}
return true;
}
The nerd in me also crawled out so I did a performance test against SequenceEquals, and this one has a slight edge.
Now, the question to ask; is this tiny, almost measurable performance gain worth adding the code to the code base and maintaining it? I very much doubt it ;o)
I knocked up a quick extension method:
namespace ExtensionMethods
{
public static class MyExtensions
{
public static bool Matches<T>(this List<T> list1, List<T> list2)
{
if (list1.Count != list2.Count) return false;
for (var i = 0; i < list1.Count; i++)
{
if (list1[i] != list2[i]) return false;
}
return true;
}
}
}
One can write a general purpose IEqualityComparer<T> for sequences. A simple one:
public class SequenceEqualityComparer<T> : IEqualityComparer<IEnumerable<T>>
{
public bool Equals(IEnumerable<T> x, IEnumerable<T> y)
{
return x.SequenceEqual(y);
}
public int GetHashCode(IEnumerable<T> obj)
{
return unchecked(obj.Aggregate(397, (x, y) => x * 31 + y.GetHashCode()));
}
}
A more fleshed out version: which should be better performing.
public class SequenceEqualityComparer<T> : EqualityComparer<IEnumerable<T>>,
IEquatable<SequenceEqualityComparer<T>>
{
readonly IEqualityComparer<T> comparer;
public SequenceEqualityComparer(IEqualityComparer<T> comparer = null)
{
this.comparer = comparer ?? EqualityComparer<T>.Default;
}
public override bool Equals(IEnumerable<T> x, IEnumerable<T> y)
{
// safer to use ReferenceEquals as == could be overridden
if (ReferenceEquals(x, y))
return true;
if (x == null || y == null)
return false;
var xICollection = x as ICollection<T>;
if (xICollection != null)
{
var yICollection = y as ICollection<T>;
if (yICollection != null)
{
if (xICollection.Count != yICollection.Count)
return false;
var xIList = x as IList<T>;
if (xIList != null)
{
var yIList = y as IList<T>;
if (yIList != null)
{
// optimization - loops from bottom
for (int i = xIList.Count - 1; i >= 0; i--)
if (!comparer.Equals(xIList[i], yIList[i]))
return false;
return true;
}
}
}
}
return x.SequenceEqual(y, comparer);
}
public override int GetHashCode(IEnumerable<T> sequence)
{
unchecked
{
int hash = 397;
foreach (var item in sequence)
hash = hash * 31 + comparer.GetHashCode(item);
return hash;
}
}
public bool Equals(SequenceEqualityComparer<T> other)
{
if (ReferenceEquals(null, other))
return false;
if (ReferenceEquals(this, other))
return true;
return this.comparer.Equals(other.comparer);
}
public override bool Equals(object obj)
{
return Equals(obj as SequenceEqualityComparer<T>);
}
public override int GetHashCode()
{
return comparer.GetHashCode();
}
}
This has a few features:
The comparison is done from bottom to top. There is more probability for collections differing at the end in typical use-cases.
An IEqualityComparer<T> can be passed to base the comparison for items in the collection.
Use linq SequenceEqual to check for sequence equality because Equals method checks for reference equality.
bool isEqual = list1.SequenceEqual(list2);
The SequenceEqual() method takes a second IEnumerable<T> sequence as a parameter, and performs a comparison, element-by-element, with the target (first) sequence. If the two sequences contain the same number of elements, and each element in the first sequence is equal to the corresponding element in the second sequence (using the default equality comparer) then SequenceEqual() returns true. Otherwise, false is returned.
Or if you don't care about elements order use Enumerable.All method:
var isEqual = list1.All(list2.Contains);
The second version also requires another check for Count because it would return true even if list2 contains more elements than list1.