Problem sorting lists using delegates - c#

I am trying to sort a list using delegates but I am getting a signature match error. The compiler says I cannot convert from an 'anonymous method'
List<MyType> myList = GetMyList();
myList.Sort( delegate (MyType t1, MyType t2) { return (t1.ID < t2.ID); } );
What am I missing?
Here are some references I found and they do it the same way.
Developer Fusion Reference
Microsoft Reference

I think you want:
myList.Sort( delegate (MyType t1, MyType t2)
{ return (t1.ID.CompareTo(t2.ID)); }
);
To sort you need something other than "true/false", you need to know if its equal to, greater than, or less than.

The Sort doesn't take a binary predicate, it takes a Comparison<T> delegate which returns an int not a bool.
The return values are 0 for when the items are equal, <0 for when the first item is less than the second, and >0 for when the first item is greater than the second.

In future, if you want to debug problems like this, I'd advocate breaking out the delegate definition from the Sort call, like this:
Comparison<MyType> c = delegate(MyType t1, MyType t2){ ... };
myList.Sort(c);
That way, you can see if the problem is in your method call, or in your delegate definition. Some people prefer to leave it this way (with a more descriptive name than "c", obviously) to make the code more readable. I could take it or leave it =-)

The way of obj.Sort(delegate(...)); is dynamic sorting in one place. If you have several places doing the same sorting or you need more flexible sorting, you may consider to create a class implementing IComparer<T>. Here is an example:
public class MyTypeComparer : IComparer<MyType>
{
public MyTypeComparer() // default comparer on ID
{ ... }
public MyTypeComparer(bool desc) // default with order specified
public MyTypeComparer(string sort, bool desc) // specified sort and order such as property name, true or false.
{ ... }
public int Compare(MyType a, MyType b) // implement IComparer interface
{ ... } // this is real sorting codes
}
and here is the example to use it:
List<MyType> myList = GetList();
myList.Sort(new MyTypeComparer());
// myList.Sort(new MyTypeComparer(false));
// myList.Sort(new MyTypeComparer("FirstName", true));

Make sure if your ID property is the default value data type, such as Int or String. If the ID is an object reference type, that object should implement IComparer or IComparer.

Sorry for previous post. The editor does not take < and > characters, and I did not notice the preview right under the editor. If the ID property is an object type, the object should implement IComparer or IComparer<T>.

Related

Know if a type can be converted to string representing the data [duplicate]

I am writing an interop between a php service and our crm. One of the things I need to do is make sure that simple types get converted ToString() for use later in a json converter.
I am not sure even what the name is for 'simple types' but it can be defined like this... "an object that represents a low level variable type, containing a single value, not a class or anything with executable functions etc"
I've found that int, string, bool, double, and surprisingly enum will ToString() with pretty predictable results.
int x = 0;
bool y = true;
double z = 1.59 // money
CustomEnum theEnum = CustomEnum.somevalue;
x.ToString() results in "0"
y.ToString() results in "true"
z.ToString() results in "1.59"
theEnum.ToString() results in "somevalue"
But if I use this:
List<int> iList = new List<int>();
iList.Add(1);
MyClass theClass = new MyClass();
iList.ToString() results in "System.Collections.Generic.List`1[System.Int32]"
theClass.ToString() results in "STTI.NKI.Interop.MyClass"
I'm not limited to lists. I could have an ExpandoObject, or a class etc.
I understand EXACTLY why this happens, and I want to know if there is a quick way to determine if an object of unknown type will ToString() into an expected value, and not the type name. I find it an antipattern to do something like
switch (theObject.GetType())
case typeof(int):
case typeof(bool):
case typeof(doulble):
etc
I am not sure what the terms are, so googling my answer is proving difficult.
So you want to check whether a type has a overridden ToString method? Why not just check whether the value returned by ToString is equal to the value returned by the default implementation of ToString?
From here, we know the default implementation of ToString is
return GetType().ToString();
So, we can use this to check whether an object has overridden the ToString method:
bool toStringOverridden = someObject.GetType().ToString() !=
someObject.ToString();
The ToString method is a virtual one and the default implementation is defined in the Object class and simply returns the name of the type of the object:
public virtual string ToString()
{
return this.GetType().ToString();
}
int for example, overrides this method to return a meaningful representation.
What you can do is use reflection to detect whether a type overrides the ToString method like this:
public static bool OverridesToString(Type type)
{
return type.GetMethod("ToString", new Type[0]).DeclaringType != typeof(object);
}
If it does, there is a very good chance that the ToString method would return something meaningful.
Option 1: make sure that every Object will overwrite ToString().
Option 2: Use reflection to get all object properties and concat them.
Maybe you can do something similar to this:
bool ToStringIsTyped<T>(T myObj)
{
return myObj.ToString().Contains(typeof(T).FullName);
}
It may not work in all cases, but possibly could be expanded
I Think this is what you are looking, in the GetMethod the second argument is an empty array to watch for the .ToString(), just convert the i.GetType().GetMethod("ToString", new Type[] { }).DeclaringType == typeof(object) to a function and there you go.
class Program
{
static void Main(string[] args)
{
int i = 55;
var s = "some string";
var x = new List<string>();
Console.WriteLine(i.ToString());
Console.WriteLine(i.GetType().GetMethod("ToString", new Type[] { }).DeclaringType == typeof(object));
Console.WriteLine(s.ToString());
Console.WriteLine(s.GetType().GetMethod("ToString",new Type[]{}).DeclaringType == typeof(object));
Console.WriteLine(x.ToString());
Console.WriteLine(x.GetType().GetMethod("ToString",new Type[]{}).DeclaringType == typeof(object));
}
}
...way to determine if an object of unknown type will ToString() into an expected value, and not the type name...
The default implementation of ToString() on object, according to documentation, returns "the fully qualified name of the object's type".
So we could come up with the hypothesis that whenever ToString() is overridden, its output will be "useful" in the sense you specified in the question.
To detect whether a function called is an override, we can make use of this answer, like so:
if(typeof(ObjectX).GetMethod("ToString").DeclaringType == typeof(ObjectX))
{
/* ObjectX has overridden ToString() */
}
else
{
/* ObjectX has inherited ToString() from its base class(es) */
}
Using reflection can add too much overhead, so I reckon it's better to create a generic method and add a constraint like: where T : IFormattable

Best way to compare two generic values?

I'm writing a small class which I'm gonna move around when needed like a dll, and it's gonna have different sorting algorithms in it. I want the functions to work with any lists, of any types, including objects. So it's basically like this:
class TemplateSortings<T>
{
List<T> GNRList;
static void SortBubble<T>()
{
//Do stuff with GNRList, which can be a list of any values (nums, strings, objects)
}
}
Now the question I'm having troubles with is this - what is the best way to compare two generic values: overloading comparison operators or having the class inherit IComparable interface? What is better and why?
If you want it to work with any type, you probably shouldn't constrain T to types that implement IComparable, because not all types do.
A simple way to work around this is to let the caller decide how to compare the objects. You just need an extra parameter:
static void SortBubble(Func<T, T, int> comparator)
{
...
}
You can call comparator with 2 arguments and it will give you a negative value, 0, or a positive value indicating that the first parameter is less than, equal to, or greater than the second parameter.
As an example, you can call SortBubble with ints like this:
var sorting = new TemplateSortings<int>();
// populate the list...
sorting.SortBubble((x, y) => x.CompareTo(y)) // pass a lambda
EDIT:
If you don't want an extra parameter and want to check the type inside the method, you can do something like this:
if (typeof(IComparable<T>).IsAssignableFrom(typeof(T))) {
// do your sorting
// you need to cast values of type "T" to "Comparable<T>" like this
// var castedValue = (IComparable<T>)tValue;
} else {
throw ...
}
You could generalize your code so it can work with any potentially valid type T:
public static IEnumerable<T> BubbleSort(
this IEnumerable<T> source,
IComparer<T> comparer == null)
{
var currentComparer = comparer ?? Comparer<T>.Default;
//bubble sort with currentComparator
}
Now, you can sort any T whatsoever, if:
T implements IComparable<T>
T implements legacy IComparable
You hand down a Comparator that knows how to compare Ts
It will fail on any other scenario the moment you attempt to perform the first comparison.

How does sorting a C# List based on a property work?

So, I'm doing an assignment for my C# class and I have a list of objects. These objects have an 'int rand' field which is assigned a random number. I then wanted to re-sort the objects in the list based on this rand field.
I found this article:
http://www.developerfusion.com/code/5513/sorting-and-searching-using-c-lists/
And it helped. I modified this line to fit my code:
people.Sort(delegate(Person p1, Person p2) { return p1.age.CompareTo(p2.age); });
And it does what I want.
What I want to know is: how does it work? That looks very confusing to me.
In fact Sort Method should sort base on some comparison, in your current code you passed comparison as delegate, you can also embed it in class definition to reduce code complexity, In fact it just needed to implement IComparable for your Person class:
public class Person : IComparable
{
public int age { get; set; }
public int CompareTo(object obj)
{
var person = obj as Person;
if (person != null)
{
if (age > person.age)
return 1;
else if (age == person.age)
return 0;
return -1;
}
return 1;
}
}
then simply use sort without delegates.
If you use Lambda notation with it gets a little easier to read IMO:
people.Sort((p1, p2) => p1.age.CompareTo(p2.age));
When you use the sort method you are sorting the list, but the method needs to know what to sort by, and this is where the delegation becomes handy as you can use the sort method to specify any sorting you want. You are looking at person 1 and person 2 and are ordering by age. If you wanted to sort by something else like a Name (If you had a Name property), you would write it as:
people.Sort((p1, p2) => string.Compare(p1.Name, p2.Name));
the list will use the function passed in (the return p1.age.CompareTo(p2.age); part) to compare the different objects in the list. It basically allows you to "teach" the list how you want the items compared.
The list will call your function, passing in 2 instances of the class that should be compared. you return -1 to say the 1st is less than the 2nd, 0 to say they are equal, and 1 to say the 2nd is greater. Your example just passes the call on to the built in comparison (that returns the same -1, 0, 1 pattern) for whatever type the age variable is, most likely an integer.
In order to sort, you need to be able to figure out if one item goes before or after another thing. It makes sense that this "comparator" would be a function or method as it compartmentalizes the knowledge away.
If you look at the documentation for CompareTo you'll notice that it's intended to return -1 (B goes before A), 0, (A and B are equal) or 1 (B goes after A).
The delegate keyword in this instance creates an anonymous function which is used as the comparator, and the body of that function calls CompareTo to compare the age property of the two people involved and return the result.
The result of calling this method on every potential pair of items (or some subset - I'm not sure exactly how Sort is implemented) is then used internally by the Sort method to figure out where to place the resulting item (in front of or behind of p2) in this example.
List.Sort uses Quick sort algo to sort the list. The worst case complexity is O(n ^ 2). Which means, in worst case, the delegate you provided will be called n ^ 2 times, where n is the number of items in list. Delegate is like pointer to function.
It passes the two objects it wishes to compare, and the delegate you provided will return with -1, 0, or 1. If its -1 it means that p1 is lesser then p2, if 0 it means both objects are same, if 1 it means p1 is greater then p2. So, in the end, the delegate you provide and the values it returns will decide whether the list contains objects in descending or ascending order.
Lets divide the problem so that you can understand each piece separately:
The Sort method:
This one takes a delegate, that contains the "how to" compare two elements of the list.
As soon as you teach the list how to compare to elements, then it can sort all elements, by comparing them in pairs.
The inline delegate
A inline delegate is the declaration of method, that does something.
delegate(Person p1, Person p2) { return p1.age.CompareTo(p2.age);
This delegate is telling how to compare two Person objects. You are telling this to the compiler: to compare p1 with p2, you should compare p1.age with p2.age.
Joining things
The following line of code contains both elements, the sort method, and the "how to" compare two People objects.
people.Sort(delegate(Person p1, Person p2) { return p1.age.CompareTo(p2.age); });
So now it knows how to sort the list.

LINQ statement no longer works after being wrapped into an extension method

I had a need for a method that could take a collection of strings, and replace all occurrences of a specific string with another.
For example, if I have a List<string> that looks like this:
List<string> strings = new List<string> { "a", "b", "delete", "c", "d", "delete" };
and I want to replace "delete" with "", I would use this LINQ statement:
strings = (from s in strings select (s=="delete" ? s=String.Empty : s)).ToList();
and it works great. But then I figured I should make it an extension method, since I'd likely use it again later. In this case, I just want to write the following:
strings.ReplaceStringInListWithAnother( "delete", String.Empty);
While my code compiles, and the LINQ statement works inside of the extension method, when I return the collection reverts back to its original contents:
public static void ReplaceStringInListWithAnother( this List<string> my_list, string to_replace, string replace_with)
{
my_list = (from s in my_list select (s==to_replace ? s=replace_with : s)).ToList();
}
So it would seem that I just modified a copy of the List... but when I looked at the code for Pop, it modifies the collection similarly, yet the changes stick, so my assumption was that my method's parameter declarations are correct.
Can anyone explain what I am doing wrong here?
The LINQ statement you wrote does not modify the collection, it actually creates a new one.
The extension method you wrote creates this new collection and then discards it. The assignment is redundant: you’re assigning to a local parameter, which goes out of scope immediately after.
When you’re calling the method, you’re also discarding its result instead of assigning it back.
Therefore, you should write the method like this:
public static List<string> ReplaceStringInListWithAnother(
this List<string> my_list, string to_replace, string replace_with)
{
return (from s in my_list select
(s == to_replace ? replace_with : s)).ToList();
}
and the call like this:
strings = strings.ReplaceStringInListWithAnother("delete", "");
By the way, you can make the function more useful by making it generic:
public static List<T> ReplaceInList<T>(this List<T> my_list,
T to_replace, T replace_with) where T : IEquatable<T>
{
return (from s in my_list select
(s.Equals(to_replace) ? replace_with : s)).ToList();
}
This way you can use it for other things, not just strings. Furthermore, you can also declare it to use IEnumerable<T> instead of List<T>:
public static IEnumerable<T> ReplaceItems<T>(this IEnumerable<T> my_list,
T to_replace, T replace_with) where T : IEquatable<T>
{
return from s in my_list select (s.Equals(to_replace) ? replace_with : s);
}
This way you can use it for any collection of equatable items, not just List<T>. Notice that List<T> implements IEnumerable<T>, so you can still pass a List into this function. If you want a list out, simply call .ToList() after the call to this one.
Update: If you actually want to replace elements in a list instead of creating a new one, you can still do that with an extension method, and it can still be generic, but you can’t use Linq and you can’t use IEnumerable<T>:
public static void ReplaceInList<T>(this List<T> my_list,
T to_replace, T replace_with) where T : IEquatable<T>
{
for (int i = 0; i < my_list.Count; i++)
if (my_list[i].Equals(to_replace))
my_list[i] = replace_with;
}
This will not return the new list, but instead modify the old one, so it has a void return type like your original.
Here's a hint: what do you expect the below code to do?
void SetToTen(int y)
{
y = 10;
}
int x = 0;
SetToTen(x);
Hopefully, you understand that the SetToTen method above does nothing meaningful, since it only changes the value of its own local variable y and has no effect on the variable whose value was passed to it (in order for that to happen, the y parameter would have to be of type ref int and the method would be called as SetToTen(ref x)).
Keeping in mind that extension methods are really just static methods in fancy clothes, it should be clear why your ReplaceStringInListWithAnother is not doing what you expected: it is only setting its local my_list variable to a new value, having no effect on the original List<string> passed to the method.
Now, it's worth mentioning that the only reason this is not working for you is that your code works by setting a variable to a new object*. If you were to modify the List<string> passed to ReplaceStringInListWithAnother, everything would work just fine:
public static void ReplaceStringInListWithAnother( this List<string> my_list, string to_replace, string replace_with)
{
for (int i = 0; i < my_list.Count; ++i)
{
if (my_list[i] == to_replace)
{
my_list[i] = replace_with;
}
}
}
It's also worth mentioning that List<string> is an overly restrictive parameter type for this method; you could achieve the same functionality for any type implementing IList<string> (and so I'd change the my_list parameter to be of type IList<string>).
*Reading your question again, it seems clear to me that this is the main point of confusion for you. The important thing you have to realize is that by default, everything in C# is passed by value. With value types (anything defined as a struct -- int, double, DateTime, and many more), the thing that's passed is the value itself. With reference types (anything that's defined as a class), the thing that's passed is a reference to an object. In the latter case, all method calls on references to objects of mutable types do actually affect the underlying object, since multiple variables of reference type can point to the same object. But assignment is different from a method call; if you assign a reference to an object that has been passed by value to some new reference to an object, you are doing nothing to the underlying object, and therefore nothing is happening that would be reflected by the original reference.
This is a really important concept that many .NET developers struggle with. But it's also a topic that's been explained thoroughly elsewhere. If you need more explanation, let me know and I'll try to dig up a link to a page that makes all of this as clear as possible.
You haven't shown the code for "Pop" so it's hard to know what you mean. You talk about "when I return the collection" but you're not returning anything - the method has a void return type.
LINQ typically doesn't change the contents of an existing collection. Usually you should return a new collection from the extension method. For example:
public static IEnumerable<string> ReplaceAll
(this IEnumerable<string> myList, string toReplace, string replaceWith)
{
return toReplace.Select(x => x == toReplace ? replaceWith : x);
}
(I've made it more general here - you shouldn't start materializing lists unless you really need to.)
You'd then call it with:
strings = strings.ReplaceAll("delete", "").ToList();
... or change the type of string to IEnumerable<string> and just use
strings = strings.ReplaceAll("delete", "");

Using IComparer<> with delegate function to search

This feels like a too easy question to be found with google, I think/hope I've got stuck in the details when trying to implement my own version of it. What I'm trying to do is to sort a list of MyClass objects depending on my Datatype object different search functions should be used.
I've had something like this in mind for the class Datatype:
class Datatype {
public delegate int CMPFN(object x, object y);
private CMPFN compareFunction;
(...)
private XsdDatatype((...), CMPFN compareFunction) {
(...)
this.compareFunction = compareFunction;
}
public CMPFN GetCompareFunction() {
return this.compareFunction;
}
static private int SortStrings(object a, object b) {
return ((MyClass)a).GetValue().CompareTo(((MyClass)b).GetValue());
}
}
And later on I'm trying to sort a MyClass list something like this:
List<MyClass> elements = GetElements();
Datatype datatype = new Datatype((...), Datatype.SortStrings);
elements.Sort(datatype.GetCompareFunction()); // <-- Compile error!
I'm not overly excited about the cast in Datatype.SortStrings but it feels like this could work(?). The compiler however disagrees and gets me this error on the last line above and I'm a bit unsure exactly why CMPFN can't be converted/casted(?) to IComparer.
Cannot convert type 'proj.Datatype.CMPFN' to 'System.Collections.Generic.IComparer<proj.MyClass>'
Delegates aren't duck-typed like that. You can create an Comparison<MyClass> from a CMPFN but you can't use a plain reference conversion - either implicit or explicit.
Three options:
Create the comparer like this:
elements.Sort(new Comparison<MyClass>(datatype.GetCompareFunction()));
Use a lambda expression to create a Comparison<T> and use that instead:
elements.Sort((x, y) => datatype.GetCompareFunction()(x, y));
Write an implementation of IComparer<MyClass> which performs the comparison based on a CMPFN
Note that the second approach will call GetCompareFunction once per comparison.
A much better solution would be to get rid of CMPFN entirely - why not just use (or implement) IComparer<MyClass> to start with? Note that that would remove the casts as well. (If you're happy using delegates instead of interfaces, you could express the comparison as a Comparison<MyClass> instead.)
Note that as of .NET 4.5, you can use Comparer.Create to create a Comparer<T> from a Comparison<T> delegate.
I'm not sure why your current API is in terms of object, but you should be aware that in C# 3 and earlier (or C# 4 targeting .NET 3.5 and earlier) you wouldn't be able to convert an IComparer<object> into an IComparer<MyClass> (via a reference conversion, anyway). As of C# 4 you can, due to generic contravariance.
There are a number of overloads of List<T>.Sort, but there are none which take a delegate with the parameters you have defined (two objects).
However, there is an overload that takes a Comparison<T> delegate, which you can work with your code with a few minor modifications. Basically, you just replace your CMPFN delegate with Comparison<MyClass> - as an added bonus, you get strong-typing in your SortStrings function, too:
static private int SortStrings(MyClass a, MyClass b) {
return a.GetValue().CompareTo(b.GetValue());
}
public Comparison<MyClass> GetCompareFunction() {
return SortStrings; // or whatever
}
...
elements.Sort(datatype.GetCompareFunction());
Try something like this
class AttributeSort : IComparer<AttributeClass >
{
#region IComparer Members
public int Compare(AttributeClass x, AttributeClass y)
{
if (x == null || y == null)
throw new ArgumentException("At least one argument is null");
if (x.attributeNo == y.attributeNo) return 0;
if (x.attributeNo < y.attributeNo) return -1;
return 1;
}
#endregion
}
You can call it then like this
List<AttributeClass> listWithObj ....
listWithObj.Sort(new AttributeSort());
Should work like you want. You can create a type-safe comparer class as well.

Categories

Resources