Hello every Linq experts,
I would like to know how can I solve the following:
There is a string array:
string[] words={"a#p#e","#pp#e","a##le"};
How can I get the word 'apple' by Linq?
Thanks a lot!
words.SelectMany(ar=>ar.Select((c,i)=>new{Index=i, Letter = c}).Where(o=>char.IsLetter(o.Letter))).OrderBy(o=>o.Index).GroupBy(o=>o).Select(g=>g.Key);
Most likely this can be simplified, but well, it works (put together quickly in LinqPad).
This assumes you're only working with letters (can be modified to use char.IsLetterOrDigit), or use other filtering in Where.
Also, especially for #MarkPeters, a query syntax, properly named version:
from partialWord in words
from characterWithPosition in partialWord.Select((character, position) => new{character,position})
where char.IsLetter(characterWithPosition.character)
orderby characterWithPosition.position
group characterWithPosition by characterWithPosition into allCharactersWithPositions
let singleCharacterWithPosition = allCharactersWithPositions.Key
select singleCharacterWithPosition.character
This should work:
string[] words = { "a#p#e", "#pp#e", "a##le" };
var apple = words
.Aggregate(
(str1, str2) => { return String.Concat(str1.Zip(str2,
(c1, c2) => c1 == '#' ? c2 : c1).ToArray());
});
It works by checking whether there are any not-wanted characters in the first string and replacing them with the corresponding characters from the second string. The merged string is then passed to the next iteration, where the next two strings are merged. Finally the result is returned.
#mrbraitwistle's answer is the proper solution; performing IEnumerable<char>.Zip method within a IEnumerable<string>.Aggregate method
This following answer provides explicit type definitions to the parts of #Gerino's answer, which uses quite a bit of anonyomous types and delegates; Additioanlly, this answer utilizes Linq.Expressions and IQueryable<T>;
There is a catch though, it is in the GetHashCode of IndexLetterPair type below.
We'll create a concrete type instead of declaring the anonymous type new { Index = i, Letter = c }; however, the GroupBy will not function properly unless we override the GetHashCode method of object (of which our type inherits). We are also going to implement the IEquatable interface (where T is another IndexLetterPair), this interface will be utlized by the IQueryable<T>.GroupBy method.
Additionally, well override the object.Equal method as well - though it is likely unnecessary to do so since the GetHashCode is overriden.
public class IndexLetterPair IEquatable<IndexLetterPair>
{
public int Index { get; set; }
public char Letter { get; set; }
public override int GetHashCode()
{
return new { Index = this.Index, Letter = this.Letter }.GetHashCode();
}
// (new IndexLetterPair() as object).Equals(new IndexLetterPair());
public override bool Equals(object obj)
{
return (this.GetHashCode() == obj.GetHashCode());
}
// new IndexLetterPair().Equals(new IndexLetterPair());
public bool Equals(IndexLetterPair other)
{
return (this.GetHashCode() == other.GetHashCode());
}
}
For convience, were going to declare an extension class and method of IQueryable<string> that executes/declares the sequence of our defined expressions.
using Linq.Expressions;
public static class MyQueryableStringExtensions
{
readonly static Func<char, int, IndexLetterPair> SelectCharIndexPairingClause = (c, i) => new IndexLetterPair() { Index = i, Letter = c };
readonly static Func<IndexLetterPair, bool> WhereIsLetter = (dyn) => char.IsLetter(dyn.Letter);
readonly static Expression<Func<string, IEnumerable<IndexLetterPair>>> ManyClause = (arr) => arr.Select(SelectCharIndexPairingClause).Where(WhereIsLetter);
readonly static Expression<Func<IndexLetterPair, int>> OrderByIndexClause = (pairing) => pairing.Index;
readonly static Expression<Func<IndexLetterPair, IndexLetterPair>> GroupByClause = (pairing) => pairing;
// if IEquatable<IndexLetterPair> is implemented ? uses IEquatable<IndexLetterPair>.Equals : (IndexLetterPair() as object).Equals
readonly static Expression<Func<IGrouping<IndexLetterPair, IndexLetterPair>, IndexLetterPair>> GroupSelectKeyClause = (pairing) => pairing.Key;
public static IQueryable<char> SelectManyGroupedLetterChars(this IQueryable<string> words)
{
return words.SelectMany(ManyClause)
.OrderBy(OrderByIndexClause)
.GroupBy(GroupByClause)
.Select(GroupSelectKeyClause)
.Select((pair) => pair.Letter);
}
}
string[] words = new string[] { "a#p#e", "#pp#e", "a##le" };
IQueryable<string> queryableWords = words.AsQueryable();
IQueryable<char> queryGroupedLetterChars = queryableWords.SelectManyGroupedLetterChars();
// string(char[]);
string word = new string(queryGroupedLetterChars.ToArray());
Related
Edit
My original question was not very clear, so I'd like to try to rephrase it now. Please let me know if I still miss the mark.
Essentially, I'm trying to return a new string, in which all substrings enclosed by brackets have been replaced by a string from an object in a list. As an abstract example, I want to do something like the following:
public class MyType () : IEquatable <Property>
{
public string id;
public override String ToString()
{
return id;
}
public bool Equals ( MyType other )
{
if ( other is MyType == false )
{
return false;
}
return this.id == other.id;
}
}
List<MyType> listOfCustomTypes = new List<MyType> ();
return Regex.Replace ( originalString, "{(.*?)}", d => listOfCustomTypes.Where ( t => t.id == d.Groups[1].Value ).FirstOrDefault ());
The problem I've run into, or, error, specifically, is Cannot convert lambda expression to delegate type (System.Text.RegularExpressions.MatchEvaluator) because some of the return types in the block are not implicitly convertible to the delegate return type.
I am assuming that it isn't allowed to use return types in delegates, or something, because I can normally access it's properties, or cast to string.
I've probably still managed to jumble my question, so if it helps, my full project can be seen here, and the relevant file for this question is here (specific line is 161).
Original Question
I'm trying to learn how to use delegates and lambdas, and in typical fashion, bit off more than I can chew. In the following code snippet, I define a class, which holds a list of classes. In another function, I'm trying to use a string to find a list item, and get a value from that item.
[XmlRoot ( "Replacers" )]
public class Replacers
{
[XmlElement ( "Property" )]
public List<Property> properties = new List<Property> ();
[XmlIgnore]
public static Replacers replacers;
}
public class Property : IEquatable <Property>
{
[XmlAttribute ( "id" )]
public string id;
[XmlElement ( "Value" )]
public List<Value> propertyValue = new List<Value> ();
public override String ToString()
{
return id;
}
public bool Equals ( Property other )
{
return this.id == other.id && this.propertyValue == other.propertyValue;
}
}
public static class GetVariable
{
public static string FromUser ( string originalString )
{
try
{
//return Regex.Replace ( originalString, "{(.*?)}", m => Replacers.replacers.properties.FindIndex ( m.Groups[1].Value ) );
} catch ( Exception e )
{
return "ERROR: Unable to find '" + Regex.Match ( originalString, "{(.*?)}" ) + "'";
}
}
}
The commented out line above is that I'm trying to figure out. How do I replace anything that matches the pattern {(.*?)} with a value from the list item of the same name.
Thanks for taking the time to consider my question!
TL;DR:
How do I iterate over a list using lambda, where the iteration returns the actual list item? As an example, I want to do something like: Regex.Replace ( input, pattern, m => myList.Where(listItem.identifier == m). I don't feel like I've made my question very clear, so please ask, if you're confused. Thank you!
Consider this example:
var foos = new[] { "aaa", "aba", "aca" };
var bars = foos.Where(f => f.Contains("b")).Select(f => Regex.Replace(f, "b", "d"));
foreach (var bar in bars)
Console.WriteLine(bar);
// Output:
ada
Edit: I'll try to address your comment
A lambda is just a shorthand for a delegate (a typed-method).
You're probably accustomed to types like int, string, double, Animal, etc.
Well, just extend that notion to method signatures.
You can think of any method signature as being a type.
Here's a method that returns a bool, and takes an int as a parameter:
bool A(int i) { ... }
So the signature can be viewed as a type.
A lambda is a shorthand for this. Here's a lambda, that takes an int, and returns a bool, just like the method signature above:
(x) => x % 2 == 0
Linq extension methods (Where(), Select(), etc) all take some delegate type, or lambda expression.
myCollection.Where(x => x % 2 == 0).Where(x => x > 10).Select(x => x * 2);
The beauty is you can keep chaining these extension methods, each one becoming an additional filter if you will.
Select() is special because it's a projection operation (it transforms the items in the collection). You can see it takes this odd parameter here:
Func<string, string> // or something like that, depends on the types in your collection
A Func is kinda like a delegate, but in a more generic sense. It's easy to understand. The first type arguments are the input parameters (think parameters of a method), and the last is the output (think the return type of a method)
Func<in, in, in, out>
Consider this:
// Here's a method signature
bool MyMethod(int a, int b)
// Here's a lambda of the same delegate type
(a, b) => a == b
// Here's a Func being assigned that lambda
Func<int, int, bool> func = (a, b) => a == b;
I have a requirement to modify a method so that it has an extra parameter that will take a lambda expression that will be used on an internal object to return the value of the given property. Forgive my probable incorrect use of terminology as this is my first foray into LINQ expressions!
I have tried searching for an answer, but as I mentioned, my terminology seems to be off and the examples I can find are far too complex or deal with expressions for collection functions such as .Where(), which I am familiar with.
What I have so far (cut down version):
class MyClass
{
private MyObject _myObject = new MyObject() { Name = "Test", Code = "T" };
private string MyMethod(int testParameter, ??? selector)
{
//return _myObject.Name;
//return _myObject.Code;
return ???;
}
}
I would like to call it something like this:
string result = _myClassInstance.MyMethod(1, (x => x.Name));
or:
string result = _myClassInstance.MyMethod(1, (x => x.Code));
Obviously the parts which I am missing is the selector parameter in MyMethod, how to apply it to the local variable and how to pass the required property into the method when I am invoking it.
Any help would be appreciated, also extra bonus points for a VB.NET solutions as well as unfortunately the final implementation needs to be in our lone VB project!
private string MyMethod(int testParameter, Func<MyObject, string> selector)
{
return selector(_myObject);
}
When using Func delegates, the last parameter is the return type and the first N-1 are the argument types. In this case, there is a single MyObject argument to selector and it returns a string.
You can invoke it like:
string name = _myClassInstance.MyMethod(1, x => x.Name);
string result = _myClassInstance.MyMethod(1, x => x.Code);
Since the return type of MyMethod matches the return type of your selector delegate, you could make it generic:
private T MyMethod<T>(int testParameter, Func<MyObject, T> selector)
{
MyObject obj = //
return selector(obj);
}
I don't know VB.Net but it looks like it would be:
Public Function MyMethod(testParameter as Integer, selector as Func(Of MyObject, String))
Return selector(_myObject)
End Function
and the generic version would be:
Public Function MyMethod(Of T)(testParameter as Integer, selector Func(Of MyObject, T))
Return selector(_myObject)
End Function
I will show you a different approach that is very flexible (see DotNetFiddle at the bottom): You can easily write your own LINQ functions to extend existing functions or write your own functions and benefit from the power of LINQ queries.
In this example, I am improving Linq's Distinct function in a way so you can specify a field, which is used for grouping.
Usage (Example):
var myQuery=(from x in Customers select x).MyDistinct(d => d.CustomerID);
In this example the query is being grouped by CustomerID and the first element of each group is returned.
Declaration of MyDistinct:
public static class Extensions
{
public static IEnumerable<T> MyDistinct<T, V>(this IEnumerable<T> query,
Func<T, V> f)
{
return query.GroupBy(f).Select(x=>x.First());
}
}
You can see that f, the 2nd parameter, is declared as Func<T, V>, so it can be used by the .GroupBy statement.
Coming back to the code in your question, if you have declared
class MyObject
{
public string Name;
public string Code;
}
private MyObject[] _myObject = {
new MyObject() { Name = "Test1", Code = "T"},
new MyObject() { Name = "Test2", Code = "Q"},
new MyObject() { Name = "Test2", Code = "T"},
new MyObject() { Name = "Test5", Code = "Q"}
};
you could use that with the newly defined function MyDistinct as follows:
var myQuery = (from x in _myObject select x).MyDistinct(d => d.Code);
which will return
Name Code
Test1 T
Test2 Q
or you can use .MyDistinct(d => d.Name) in the query, which returns:
Name Code
Test1 T
Test2 Q
Test5 Q
Notice that because MyDistinct is declared with the generics T and V, it recognizes and uses the right object types automatically and returns MyObject elements.
Advanced usage
Notice that MyDistinct always takes the first element of each group. What if you need a condition defining which element you need?
Here's how you can do it:
public static class Extensions
{
public static IEnumerable<T> MyDistinct<T, V>(this IEnumerable<T> query,
Func<T, V> f,
Func<IGrouping<V,T>,T> h=null)
{
if (h==null) h=(x => x.First());
return query.GroupBy(f).Select(h);
}
}
This modification either allows you to use it exactly as before, i.e. by specifying one parameter like .MyDistinct(d => d.Name), but it also allows you to specify a having condition such as x => x.FirstOrDefault(y => y.Name.Contains("1")||y.Name.Contains("2")) as a second parameter like so:
var myQuery2 = (from x in _myObject select x).MyDistinct(d => d.Name,
x=>x.FirstOrDefault(y=>y.Name.Contains("1")||y.Name.Contains("2"))
);
If you run this query, the result is:
Name Code
Test1 T
Test2 Q
null
because Test5 does not meet the condition (it does not contain 1 or 2), you're getting null in the 3rd row.
Note: If you want to expose just the condition, you can have it even simpler by implementing it as:
public static IEnumerable<T> MyDistinct2<T, V>(this IEnumerable<T> query,
Func<T, V> f,
Func<T,bool> h=null
)
{
if (h == null) h = (y => true);
return query.GroupBy(f).Select(x=>x.FirstOrDefault(h));
}
In this case, the query would just look like:
var myQuery3 = (from x in _myObject select x).MyDistinct2(d => d.Name,
y => y.Name.Contains("1") || y.Name.Contains("2")
);
so you don't need to write x=>x.FirstOrDefault(... condition ...).
Try it in DotNetFiddle
in C#
The parameter type you are looking for Func
private string MyMethod(int testParameter, Func<MyClass,string> selector){
return selector(_myObject);
}
in VB you still want Func the syntax is a little different.
Function MyMethod(ByVal testParameter As Integer, ByVal selector as Func(Of MyClass,string) as string
return selector(_myObject)
End Function
class MyClass
{
private MyObject _myObject = new MyObject() { Name = "Test", Code = "T" };
private string MyMethod(int testParameter, Func<MyObject, string> selector)
{
return selector(_myObject );
}
}
You can do that with a delegate of your selector:
delegate string SampleDelegate(MyObject obj);
private string MyMethod(int testParameter, SampleDelegate selector)
{
return selector(_myObject);
}
You are probably looking for the Delegate class ("Delegate" in VB, "delegate" in C#), or one of its subtypes.
This page has some examples you will probably find useful, especially near the bottom of the page.
Here is a VB example of what you would want to do:
Public Class MyClass
Private Property _myObject As MyObject = New MyObject With {.Name = "Test", .Code = "T"}
Private Function MyMethod(testParameter As Integer, selector As Func(Of MyObject, String)) As String
Return selector(_myObject).ToString
End Function
End Class
In C# if I want to see if a variable is equal to one of a set of fixed values, I currently do this...
bool result = ( (x==MyEnum.A) || (x==MyEnum.B) || (x==42) );
...which to me is cumbersome. Is there anything similar to this pseudo-code?
bool result = x in {MyEnum.A, MyEnum.B, 42};
I know I can create an array inline with the values, then use LINQ across that, but are there any other options?
This is probably a BAD idea, but you can turn Contains on its head and get syntax similar to what you ask in your question with a new extension method:
//Generic. All items in the set and the candidate must be the same type.
public static bool In<T>(this T item, params T [] set)
{
return set.Contains(item);
}
bool result = x.In(MyEnum.A, MyEnum.B, MyEnum.C);
//Non-generic and non-typesafe. Anything goes. Use with care!
public static bool In(this object item, params object [] set)
{
return set.Contains(item);
}
bool result = x.In(MyEnum.A, MyEnum.B, 42);
//int-specific.
public static bool In(this int item, params int [] set)
{
return set.Contains(item);
}
bool result = x.In((int)MyEnum.A, (int)MyEnum.B, 42);
Using LINQ, you can reverse this (test if x is in a list) by using Contains:
var myList = new[] {MyEnum.A, MyEnum.B, (MyEnum)42};
result = myList.Contains(x);
var result = new[] { (int)MyEnum.A, (int)MyEnum.B, 42 }.Contains(x);
or even better:
Create extension method:
public static bool ContainedIn(this MyEnum input, params MyEnum[] parameters)
{
return parameters.Contains(input);
}
var result = x.ContainedIn(MyEnum.A, MyEnum.B);
and if you want to allow multiple types you can use object as the params type
You can take advantage of the Enumerable.Contains() extension method, which is available for all IEnumerable types:
public static bool Contains<TSource>(this IEnumerable<TSource> source, TSource value);
The syntax is still a little ugly, but you can get close to what you want:
public enum MyEnum
{
A, B, C
}
public static void Test()
{
MyEnum x = MyEnum.C;
bool result = new[] { MyEnum.A, MyEnum.B, (MyEnum)42 }.Contains(x);
}
If your list is too long but values you look for is ordered in your enum definition, you can create a range and call Contains() on it like this:
bool result = Enumerable.Range((int)MyEnum.First,(int)MyEnum.Last)
.Contains((int)x);
This will come in handy on conditions above but I wanted to post this because you did not want to create an inline array.
I can't work out how to do a "find" on a List I have based on use of a value that I'll pass in at run time. If you see my below code, I want to be able to find the CustomClass in the List for which it's Path parameter is equal to X, where X will be defined at run time.
Any ideas how to do such a find on a List? Or is this not possible without writing an iterator and doing the find manually? In which case perhaps there is a key'ed collection I should look at using instead?
private List<CustomClass> files;
public void someMethod()
{
Uri u= new Uri(www.test.com);
CustomClass cc = this.files.find( matchesUri(u) ); // WON'T LET ME DO THIS
}
private static bool matchesUri(List<CustomClass> cc, Uri _u)
{
return cc.Path == _u; }
public class CustomClass
{
private Uri path;
public Uri Path
{
get { return this.path; }
set { this.path = value; }
}
}
PS. I must admit I don't quite follow the predicate stuff in the doco at http://msdn.microsoft.com/en-us/library/x0b5b5bc.aspx
Use a lambda:
Uri u = new Uri("www.test.com");
CustomClass cc = this.files.Find(cc => cc.Path == u);
or if you still want a named method:
static bool matchesUri(CustomClass cc, Uri _u)
{
return cc.Path == _u;
}
Uri u = new Uri("www.test.com");
CustomClass cc = this.files.Find(cc => matchesUri(cc, u));
You can write
CustomClass cc = this.files.Find( p=> p.Path == u );
The Find() method returns null if no element was found that matches the predicate.
For completeness sake only, here is what you would do if you didn't want to use a lambda:
// Predicate must be a method with a single parameter,
// so we must pass the other parameter in constructor
public class UriMatcher
{
private readonly Uri _u;
public UriMatcher(Uri u)
{
_u = u;
}
// Match is Predicate<CustomClass>
public bool Match(CustomClass cc)
{
return cc.Path == _u;
}
}
And then use it as:
public void someMethod()
{
Uri u = new Uri("www.test.com");
UriMatcher matcher = new UriMatcher(u);
CustomClass cc = this.files.Find(matcher.Match);
}
Note that you are passing a reference to a method, not the result of the method -- Match vs Match().
Check this thread also: Predicate Delegates in C#.
public void someMethod()
{
Uri u= new Uri("www.test.com");
CustomClass cc = this.files.find( p => { return p.Path == u; } );
}
Try using anonymous method for search and use any local variable you wish inside of it. If that is not satisfactory, call out your normally defined delegate method.
.NET 2.0 answer using an anonymous delegate (note that this only works for C#, VB.NET does not have anonymous delegates).
public void someMethod()
{
Uri u= new Uri("www.test.com");
CustomClass cc = this.files.find(delegate(CustomClass oTemp) { return oTemp.Path == u;});
}
In Pavel's post marked as answer, I think the line:
CustomClass cc = this.files.Find(cc => cc.Path == u);
should be instead like:
CustomClass cc = this.files.Find(cc2 => cc2.Path == u);
This is because the expresion to the left of => is a variable definition (the type is inferred from the expression) - The compiler would gives a redefinition error otherwise.
This expression can also be written with an explicit definition as:
CustomClass cc = this.files.Find((CustomClass cc2) => cc2.Path == u);
Here is a solution that I used. I needed to pass several arguments and didn't want to use anything that would prevent me from editing the method during runtime, so I came up with this.
Obviously if you wanted to you could change it to a generic method (right term?) using type arguments. This also gets around the problem of lambdas in a method. Not sure if that applies to anonymous methods as well or not, but it is already separate so no big deal.
I don't know whether the reflection would have a performance hit or not.
private Predicate<ItemData> FindItemData(string search, string fieldName)
{
var field = typeof(ItemData).GetField(fieldName);
return delegate(ItemData item) { return (string)field.GetValue(item) == search; };
}
//in another method...
itemlist.Find(FindItemData(e.Row[2].ToString(), "ItemName"));
I am getting strange behaviour using the built-in C# List.Sort function with a custom comparer.
For some reason it sometimes calls the comparer class's Compare method with a null object as one of the parameters. But if I check the list with the debugger there are no null objects in the collection.
My comparer class looks like this:
public class DelegateToComparer<T> : IComparer<T>
{
private readonly Func<T,T,int> _comparer;
public int Compare(T x, T y)
{
return _comparer(x, y);
}
public DelegateToComparer(Func<T, T, int> comparer)
{
_comparer = comparer;
}
}
This allows a delegate to be passed to the List.Sort method, like this:
mylist.Sort(new DelegateToComparer<MyClass>(
(x, y) => {
return x.SomeProp.CompareTo(y.SomeProp);
});
So the above delegate will throw a null reference exception for the x parameter, even though no elements of mylist are null.
UPDATE: Yes I am absolutely sure that it is parameter x throwing the null reference exception!
UPDATE: Instead of using the framework's List.Sort method, I tried a custom sort method (i.e. new BubbleSort().Sort(mylist)) and the problem went away. As I suspected, the List.Sort method passes null to the comparer for some reason.
This problem will occur when the comparison function is not consistent, such that x < y does not always imply y < x. In your example, you should check how two instances of the type of SomeProp are being compared.
Here's an example that reproduces the problem. Here, it's caused by the pathological compare function "compareStrings". It's dependent on the initial state of the list: if you change the initial order to "C","B","A", then there is no exception.
I wouldn't call this a bug in the Sort function - it's simply a requirement that the comparison function is consistent.
using System.Collections.Generic;
class Program
{
static void Main()
{
var letters = new List<string>{"B","C","A"};
letters.Sort(CompareStrings);
}
private static int CompareStrings(string l, string r)
{
if (l == "B")
return -1;
return l.CompareTo(r);
}
}
Are you sure the problem isn't that SomeProp is null?
In particular, with strings or Nullable<T> values.
With strings, it would be better to use:
list.Sort((x, y) => string.Compare(x.SomeProp, y.SomeProp));
(edit)
For a null-safe wrapper, you can use Comparer<T>.Default - for example, to sort a list by a property:
using System;
using System.Collections.Generic;
public static class ListExt {
public static void Sort<TSource, TValue>(
this List<TSource> list,
Func<TSource, TValue> selector) {
if (list == null) throw new ArgumentNullException("list");
if (selector == null) throw new ArgumentNullException("selector");
var comparer = Comparer<TValue>.Default;
list.Sort((x,y) => comparer.Compare(selector(x), selector(y)));
}
}
class SomeType {
public override string ToString() { return SomeProp; }
public string SomeProp { get; set; }
static void Main() {
var list = new List<SomeType> {
new SomeType { SomeProp = "def"},
new SomeType { SomeProp = null},
new SomeType { SomeProp = "abc"},
new SomeType { SomeProp = "ghi"},
};
list.Sort(x => x.SomeProp);
list.ForEach(Console.WriteLine);
}
}
I too have come across this problem (null reference being passed to my custom IComparer implementation) and finally found out that the problem was due to using inconsistent comparison function.
This was my initial IComparer implementation:
public class NumericStringComparer : IComparer<String>
{
public int Compare(string x, string y)
{
float xNumber, yNumber;
if (!float.TryParse(x, out xNumber))
{
return -1;
}
if (!float.TryParse(y, out yNumber))
{
return -1;
}
if (xNumber == yNumber)
{
return 0;
}
else
{
return (xNumber > yNumber) ? 1 : -1;
}
}
}
The mistake in this code was that Compare would return -1 whenever one of the values could not be parsed properly (in my case it was due to wrongly formatted string representations of numeric values so TryParse always failed).
Notice that in case both x and y were formatted incorrectly (and thus TryParse failed on both of them), calling Compare(x, y) and Compare(y, x) would yield the same result: -1. This I think was the main problem. When debugging, Compare() would be passed null string pointer as one of its arguments at some point even though the collection being sorted did not cotain a null string.
As soon as I had fixed the TryParse issue and ensured consistency of my implementation the problem went away and Compare wasn't being passed null pointers anymore.
Marc's answer is useful. I agree with him that the NullReference is due to calling CompareTo on a null property. Without needing an extension class, you can do:
mylist.Sort((x, y) =>
(Comparer<SomePropType>.Default.Compare(x.SomeProp, y.SomeProp)));
where SomePropType is the type of SomeProp
For debugging purposes, you want your method to be null-safe. (or at least, catch the null-ref. exception, and handle it in some hard-coded way). Then, use the debugger to watch what other values get compared, in what order, and which calls succeed or fail.
Then you will find your answer, and you can then remove the null-safety.
Can you run this code ...
mylst.Sort((i, j) =>
{
Debug.Assert(i.SomeProp != null && j.SomeProp != null);
return i.SomeProp.CompareTo(j.SomeProp);
}
);
I stumbled across this issue myself, and found that it was related to a NaN property in my input. Here's a minimal test case that should produce the exception:
public class C {
double v;
public static void Main() {
var test =
new List<C> { new C { v = 0d },
new C { v = Double.NaN },
new C { v = 1d } };
test.Sort((d1, d2) => (int)(d1.v - d2.v));
}
}