Sort list by property/anonymous function? - c#

I've got a list defined like this...
var sets = new List<HashSet<int>>(numSets);
Why isn't there an overload so I can sort it like this?
sets.Sort(s => s.Count);
I want the largest set first. What's the easiest way to do that?

Because List<T> class was introduced in .NET 2.0 and the designers of this class decided so. You could use the OrderByDescending extension method:
sets = sets.OrderByDescending(s => s.Count).ToList();

Try this:
sets.Sort((setA, setB) => setB.Count.CompareTo(setA.Count));
This uses the Sort(Comparison<T> comparison) overload of List<T>.Sort.
The fact that the expression compares B with A rather than A with B is what produces the descending-by-count order that you require.
The reason your code doesn't work is because List<T>.Sort, unlike Enumerable.OrderByDescending, does not have an overload that accepts a Func<TSource, TKey> key-selector.
#Darin Dimitrov's technique of using OrderByDescending is fine too, but note that this will create a sorted list out of place and reassign the reference you have to the original list to the new, sorted one.

Related

Is there a version of null but for list?

I have a unit test that I am trying to write.
I have this section as part of a working version:
List<MyClass> queryResult = new List<MyClass>(){};
A.CallTo(() => _dataContext.GetAll<MyClass>()).Returns(queryResult.AsQueryable());
However, I would rather put something like "null" instead of "queryResult.AsQueryable()", Then there would be no need to create an empty list.
But GetAll will return a list empty or full by the looks of things. Therefore, null won't work.
Is there something like "List.Empty" that I can use instead?
Thanks
There are Array.Empty<T>() and Enumerable.Empty<T>() that might work for you. Neither of them allocates a new object per-call (they are both backed by a static T[] field on a generic class - EmptyArray<T>.Value or EmptyEnumerable<T>.Instance, although these are both implementation details)
You can use
Enumerable.Empty<MyClass>().ToList()
But I can not see any differences in this case.

C# equivalent of hasSameSizeAs()

To check that two Iterable have same size, I can write with Java's assertJ
assertThat(elvesRings).hasSameSizeAs(trilogy);
What would be the closest equivalent in C#?
So far I only have
Assert.AreEqual(elvesRings.Count, trilogy.Count);
With the FluentAssertions you can use:
elvesRings.Should().HaveSameCount(trilogy);
Link for library:
https://www.nuget.org/packages/FluentAssertions
The easiest way to do this is to just call count on each IEnumerable<T> (similar to Java's Iterable interface):
Assert.AreEqual(elvesRings.Count(), trilogy.Count());
Notice that Count is called as a method and not a property. This is because when using IEnumerable<T> count is an extension method, and when called with no parameters it simply counts everything within the underlying collection, even if that collection does not have a Count property.
This will work for both MS-TEST and NUnit.
Trivially easy to roll your own extension method to do exactly this, something along the lines of:
public static bool hasSameSizeAs(this IEnumerable first, IEnumerable second)
{
return first.Count() == second.Count();
}
Disclaimer: Error checking, potential multiple iterations of the IEnumerable, etc.

Sort an array of strings in C#

How can I sort an array of strings using the OrderBy function? I saw I need to implement some interfaces...
You can sort the array by using.
var sortedstrings = myStringArray.OrderBy( s => s );
This will return an instance of Ienumerable. If you need to retain it as a array, use this code instead.
myStringArray = myStringArray.OrderBy( s => s ).ToArray();
I'm not sure what you are referring to when you said that you have to implement some interfaces, but you do not have to do this when using the IEnumerable.OrderBy. Simply pass a Func<TSource, TKey> in the form of a lambda-expression.
OrderBy won't sort the existing array in place. If you need to do that, use Array.Sort.
OrderBy always returns a new sequence - which of course you can convert to an array and store a reference to in the original variable, as per Øyvind's answer.
To sort inside an existing array, call Array.Sort(theArray).
Re your comment on interfaces: you don't need to add any interfaces here, since string is well supported; but for custom types (of your own) you can implement IComparable / IComparable<T> to enable sorting. You can also do the same passing in an IComparer / IComparer<T>, if you want (or need) the code that provides the ordering to be separate to the type itself.
Linq has two (syntax) ways to sort an array of strings.
1:
string[] sortedStrings = unsortedStrings.OrderBy(s => s).ToArray();
This syntax is using a Lambda Expressions if you don't know what s => s means.
2:
sortedStrings = (from strings in unsortedStrings
orderby strings
select strings).ToArray();
This example looks a bit like a SQL statement and is probably easier to read if you are new with Linq.
ToArray() converts the IOrderedEnumerable<string> to as string[] in this case.

lambda expressions on populated lists

There are a few posts on the site about how to order by using lambda expressions however I cannot seem to get mine to work. I am trying to reorder a list that is already populated. Am i wrong in thinking that i can rearrange the order of this list using lambada expressions?
QuarterMileTimes.OrderByDescending(c => c.PquartermileTime);
I was wondering if it's down to PquartermileTime being a string? I also tried this expression on a date
QuarterMileTimes.orderBy(c => c.RaceDay);
Still no luck where am I going wrong?
When you call OrderByDescending, the method returns a new IEnumerable<T> - it does not reorder the collection in place.
Try doing:
QuarterMileTimes = QuarterMileTimes.OrderByDescending(c => c.PquartermileTime).ToList();
(This is if your collection is a List<T>...)
The result of OrderByDescending (and all of the other Enumerable extension methods) is an IEnumerable<T> that projects the source data in the order you're describing. It does not alter the original data in any way.
If you prefer, you can use the ToList() extension method to create a new List<T> from that result and assign it back to the original variable.
QuarterMileTimes = QuarterMileTimes.OrderByDescending(/*...*/).ToList();
(This is assuming, of course, that QuarterMileTimes is a List<T>)
The gist of the answer is no, OrderByDescending does not alter the data source in any way.
You are assigning it to a new variable aren't you?
var sortedTimes = QuarterMileTimes.OrderByDescending(c => c.PquartermileTime);
It isn't like e.g. the List.Sort method, that sorts the existing list.
The result of the method has to be assigned to a variable.
OrderByDescending returns an IOrderedEnumerable<T> i.e. a new sequence with the items in the specified order. You'll have to re-assign QuarterMileTimes to get the behaviour you expect:
QuarterMileTimes = QuarterMileTimes.OrderByDescending(c => c.PquarterMileTime).ToList();
Alternatively you can just use the returned sequence separately, which is the usual approach.
QuarterMileTimes.OrderByDescending(c => c.PquartermileTime) returns a new enumerable, ordered by PquartermileTime. It does not reorder QuarterMileTimes in place.

Simple form of Array class and Enum.GetValues()

I am working with the static method
Enum.GetValues(typeof(SomeEnum));
This method works great when all you need to do is enumerate the values, but for some reason it returns a very simple form of the Array class. I am trying to find an easy way to turn it's return value into a more "normal" collection class like a regular array or List<>.
So far if I want to do that I have to enumerate through the output of Enum.GetValues(typeof(SomeEnum)); and add them one by one to a List<>.
Any ideas how to do this more cleanly?
Answer:
The key is to cast the return result --
SomeEnum[] enums = (SomeEnum[]) Enum.GetValues(typeof(SomeEnum));
If you need a List then jus wrap it in parenthesis and ToList it like so:
List<SomeEnum> list = ((SomeEnum[]) Enum.GetValues(typeof(SomeEnum))).ToList();
If you're using .NET 3.5, you can also use Cast<T> and ToList extension methods.
IEnumerable<SomeEnum> enums = Enum.GetValues(typeof(SomeEnum)).Cast<SomeEnum>();
You can also get a list if you want to
List<SomeEnum> list = Enum.GetValues(typeof(SomeEnum)).Cast<SomeEnum>().ToList();
Inspired by Jon Skeet's unconstrained-melody, I came up with version I like more:
public static class Enum<T>
where T: struct
{
static Enum()
{
Trace.Assert(typeof(T).IsEnum);
Values = Array.AsReadOnly((T[])Enum.GetValues(typeof(T)));
}
public static readonly ReadOnlyCollection<T> Values;
}
and usage:
var values = Enum<BindingFlags>.Values;
Good thing is this version works faster for multiple calls because it does not create new array on every time.
I found here you can just do this:
SomeEnum[] enums = (SomeEnum[]) Enum.GetValues(typeof(SomeEnum));
And if you need a List just use .ToList() at the end, like this:
List<SomeEnum> list = ((SomeEnum[]) Enum.GetValues(typeof(SomeEnum))).ToList();
Or if you like this better:
List<SomeEnum> list2 = new List<SomeEnum>((SomeEnum[]) Enum.GetValues(typeof(SomeEnum)));
I have a brand new library (UnconstrainedMelody) which helps with this. It can return the values in a strongly typed array or in an immutable list:
SomeEnum[] array = Enums<SomeEnum>.GetValuesArray()
IList<SomeEnum> list = Enums<SomeEnum>.GetValues();
It's generic and has a constraint on the type parameter to make sure it's genuinely an enum. This isn't possible in normal C#, but the library does a bit of furtling to make it work. I like the second form more, because we cache the list - the fact that it's immutable means we can return the same reference again and again.
There are various other utility methods to make it easier to work with flags enums etc.
Enjoy.
This should work:
List<MyEnum> enums = ((MyEnum[])Enum.GetValues(typeof(MyEnum))).ToList();
The reason ToList() didn't work in the solution you posted in your question was that you're missing a set of parens around the casted portion. Hope this helps!
REVISION (12-Sep-2009 ~2:20 PM EST):
So, I made this suggestion last night on the basis that Enum.GetValues returns an Array, and I thought that Array implements IEnumerable<T>:
I believe you can construct a
List<T> passing any IEnumerable<T>
as a parameter into the constructor.
So you should be able to just do this:
List<SomeEnum> values = new List<SomeEnum>(Enum.GetValues(typeof(SomeEnum)));
However, GordonG quite promptly replied to my answer indicating that it doesn't compile. (Ordinarily I would test my answer, but I was at a computer without any development tools at the time and was also feeling quite [unreasonably] sure of myself.)
After some downvotes and heavy soul-searching I resolved to get to the bottom of this matter (after a good night's sleep). Turns out, according to Microsoft's documentation on the Array class here, that Array does implement IEnumerable<T>, but only at run time (so, not at compile time--hence the failure to compile). This, in hindsight, makes sense: Enum.GetValues is not a generic method, and so it cannot know what sort of generic collection to return beforehand. (At least that's how I understand it.)
Anyway, what this all means is that you can legally cast an Array to an IEnumerable<T> provided that you get your type right. And so, at last I can present my final answer, which is really the same as my original answer but with a simple cast thrown in to make everything legal:
// splitting into two lines just for readability's sake
List<SomeEnum> values;
values = new List<SomeEnum>((IEnumerable<T>) Enum.GetValues(typeof(SomeEnum)));
Of course, in retrospect, GordonG wasn't dead set on getting a List<T>, which means his own answer of casting to SomeEnum[] is really just as good.
Updated solution (from 'Konstantin Spirin') for .NET framework 2.0:
public static class Enum<T> where T : struct
{
static Enum()
{
Trace.Assert(typeof(T).IsEnum);
}
public static ReadOnlyCollection<T> Values = new ReadOnlyCollection<T>(((T[])Enum.GetValues(typeof(T))));
}
How about this:
List<SomeEnum> list = new List<SomeEnum>();
foreach (SomeEnum value in Enum.GetValues (typeof (SomeEnum)))
{
if (condition)
list.Add(value);
}

Categories