OrderBy without lambda for simple IEnumerables - c#

Is there a simpler way to write the following? I.E., without the lambda.
var strings = new[] { "Alabama", "Mississippi", "Louisiana" };
var ordered = strings.OrderBy(x => x);
Seems like it should be possible, since string implements IEquatable<string>.

It's IComparable that matters more thanIEquatable here, but it is possible:
Array.Sort(strings);
This works because strings is already an array. Since you asked for any IEnumerable:
var ary = strings.ToArray();
Array.Sort(ary);
Note the extra variable is also important in this second sample, because Array.Sort() sorts the actual object passed without returning the results, and calling .ToArray() created a new array that was then thrown away. Without the extra variable, you lose your work.
There is a similar sort method on the List<T> object you can use, as well.
You can also make your own extension method for this:
public static class MyExtensions
{
public static IOrderedEnumerable<T> Sort(this IEnumerable<T> items) where T : IComparable
{
return items.OrderBy(i => i);
}
}
And now you could just say:
var ordered = strings.Sort();

For .NET 7 or higher, use Order.
var strings = new[] { "Alabama", "Mississippi", "Louisiana" };
var ordered = strings.Order();
dotnet/runtime#67194

Related

Get generic type from an instance

I have a list that contains objects of type IMyClass.
This list contains instances of typed class MyClass<`T>.
I need to take two random objects from the list of the same MyClass type and perform an operation on them.
My code:
var item1 = list[random.Next(list.Count)];
...
var subset = list.OfType<MyClass<item1_T>>().ToList();
var item2 = subset[random.Next(subset.Count)];
What do I have to fill in at the dots to get the type item1_T?
Unfortunately in C# it is no possible to dynamically specify a generic type using the angle brackets notation as you wrote:
var subset = list.OfType<MyClass<item1_T>>().ToList();
Although you certainly could call OfType<> method using reflection:
var list = new List<IMyClass> { ... };
var item1_T = typeof(int);
var subset = (typeof(Enumerable)
.GetMethod(nameof(Enumerable.OfType))
.MakeGenericMethod(typeof(MyClass<>).MakeGenericType(item1_T))
.Invoke(null, new object[]{ list }) as IEnumerable<IMyClass>)
.ToList();
But that would be quite inefficient.
A much faster way would be:
var typeToFind = typeof(MyClass<>).MakeGenericType(item1_T);
var subset = list.Where(item => item != null && item.GetType() == typeToFind).ToList();
If this code is not performance critical, probably it wouldn't matter if you use this solution, otherwise I'd suggest to refactor the code to avoid using reflection.
In IMyClass add this line:
bool AreInterchangable(IMyClass otherInstance);
Implement in MyClass<`T>:
public bool AreInterchangable(IMyClass otherInstance)
{
return otherInstance is IMyClass<T>;
}
Instead of var subset = list.OfType<MyClass<item1_T>>().ToList(); use this:
var subset = list.Where(item => item.AreInterchangable(item1));
Note that I also introduced a generic interface IMyClass<T> which sits between IMyClass and MyClass<T>

Create an enumeration of one

If I want an empty enumeration, I can call Enumerable.Empty<T>(). But what if I want to convert a scalar type to an enumeration?
Normally I'd write new List<string> {myString} to pass myString to a function that accepts IEnumerable<string>. Is there a more LINQ-y way?
You can use Repeat:
var justOne = Enumerable.Repeat(value, 1);
Or just an array of course:
var singleElementArray = new[] { value };
The array version is mutable of course, whereas Enumerable.Repeat isn't.
Perhaps the shortest form is
var sequence = new[] { value };
There is, but it's less efficient than using a List or Array:
// an enumeration containing only the number 13.
var oneIntEnumeration = Enumerable.Repeat(13, 1);
You can also write your own extension method:
public static class Extensions
{
public static IEnumerable<T> AsEnumerable<T>(this T item)
{
yield return item;
}
}
Now I haven't done that, and now that I know about Enumerable.Repeat, I probably never will (learn something new every day). But I have done this:
public static IEnumerable<T> MakeEnumerable<T>(params T[] items)
{
return items;
}
And this, of course, works if you call it with a single argument. But maybe there's something like this in the framework already, that I haven't discovered yet.

How to change a LINQ list into an arraylist

I have to write a query in a web application using LINQ but I need to change that query into an array list. How can I change the query below to do this?
var resultsQuery =
from result in o["SearchResponse"]["Web"]["Results"].Children()
select new
{
Url = result.Value<string>("Url").ToString(),
Title = result.Value<string>("Title").ToString(),
Content = result.Value<string>("Description").ToString()
};
If you really need to create an ArrayList, you can write new ArrayList(resultsQuery.ToArray()).
However, you should use a List<T> instead, by writing resultsQuery.ToList().
Note that, in both cases, the list will contain objects of anonymous type.
There is a .ToArray() method that'll convert IEnumerable to an Array.
ArrayList doesn't have a constructor or Add(Range) method that takes an IEnumerable. So that leaves two choices:
Use an intermediate collection that does implement ICollection: as both Array and List<T> implement ICollection can be used via the ToArray() or ToList() extension methods from LINQ.
Create an instance of ArrayList and then add each element of the result:
var query = /* LINQ Expression */
var res = new ArrayList();
foreach (var item in query) {
res.Add(item);
}
The former method is simple to do but does mean creating the intermediate data structure (which of the two options has a higher overhead is an interesting question and partly depends on the query so there is no general answer). The latter is more code and does involve growing the ArrayList incrementally (so more memory for the GC, as would be the case for an intermediate Array or List<T>).
If you just need this in one place you can just do the code inline, if you need to do it in multiple places create your own extension method over IEnumerable<T>:
public static class MyExtensions {
public static ArrayList ToArrayList<T>(this IEnumerable<T> input) {
var col = input as ICollection;
if (col != null) {
return new ArrayList(col);
}
var res = new ArrayList();
foreach (var item in input) {
res.Add(item);
}
return res;
}
}

Using Linq to run a method on a collection of objects?

This is a long shot, I know...
Let's say I have a collection
List<MyClass> objects;
and I want to run the same method on every object in the collection, with or without a return value. Before Linq I would have said:
List<ReturnType> results = new List<ReturnType>();
List<int> FormulaResults = new List<int>();
foreach (MyClass obj in objects) {
results.Add(obj.MyMethod());
FormulaResults.Add(ApplyFormula(obj));
}
I would love to be able to do something like this:
List<ReturnType> results = new List<ReturnType>();
results.AddRange(objects.Execute(obj => obj.MyMethod()));
// obviously .Execute() above is fictitious
List<int> FormulaResults = new List<int>();
FormulaResults.AddRange(objects.Execute(obj => ApplyFormula(obj)));
I haven't found anything that will do this. Is there such a thing?
If there's nothing generic like I've posited above, at least maybe there's a way of doing it for the purposes I'm working on now: I have a collection of one object that has a wrapper class:
class WrapperClass {
private WrappedClass wrapped;
public WrapperClass(WrappedClass wc) {
this.wrapped = wc;
}
}
My code has a collection List<WrappedClass> objects and I want to convert that to a List<WrapperClass>. Is there some clever Linq way of doing this, without doing the tedious
List<WrapperClass> result = new List<WrapperClass>();
foreach (WrappedClass obj in objects)
results.Add(new WrapperClass(obj));
Thanks...
Would:
results.AddRange(objects.Select(obj => ApplyFormula(obj)));
do?
or (simpler)
var results = objects.Select(obj => ApplyFormula(obj)).ToList();
I think that the Select() extension method can do what you're looking for:
objects.Select( obj => obj.MyMethod() ).ToList(); // produces List<Result>
objects.Select( obj => ApplyFormula(obj) ).ToList(); // produces List<int>
Same thing for the last case:
objects.Select( obj => new WrapperClass( obj ) ).ToList();
If you have a void method which you want to call, here's a trick you can use with IEnumerable, which doesn't have a ForEach() extension, to create a similar behavior without a lot of effort.
objects.Select( obj => { obj.SomeVoidMethod(); false; } ).Count();
The Select() will produce a sequence of [false] values after invoking SomeVoidMethod() on each [obj] in the objects sequence. Since Select() uses deferred execution, we call the Count() extension to force each element in the sequence to be evaluated. It works quite well when you want something like a ForEach() behavior.
If the method MyMethod that you want to apply returns an object of type T then you can obtain an IEnumerable<T> of the result of the method via:
var results = objects.Select(o => o.MyMethod());
If the method MyMethod that you want to apply has return type void then you can apply the method via:
objects.ForEach(o => o.MyMethod());
This assumes that objects is of generic type List<>. If all you have is an IEnumerable<> then you can roll your own ForEach extension method or apply objects.ToList() first and use the above syntax .
The C# compiler maps a LINQ select onto the .Select extension method, defined over IEnumerable (or IQueryable which we'll ignore here). Actually, that .Select method is exactly the kind of projection function that you're after.
LBushkin is correct, but you can actually use LINQ syntax as well...
var query = from o in objects
select o.MyMethod();
You can also run a custom method using the marvelous Jon Skeet's morelinq library
For example if you had a text property on your MyClass that you needed to change in runtime using a method on the same class:
objects = objects.Pipe<MyClass>(class => class.Text = class.UpdateText()).ToList();
This method will now be implemented on every object in your list. I love morelinq!
http://www.hookedonlinq.com/UpdateOperator.ashx has an extended Update method you can use. Or you can use a select statement as posted by others.

Linq return IEnumerable<MyObject>, how to return MyListObject instead?

Is there a way without looping all the IEnumerable to get back the data inside the object (that inherited BindingList)?
MyListObject--> Transformed with Linq --> Back the data inside MyListObject
I know that I can do .ToList but it doesn't do what I would like.
Any idea? Thank :)
I'm not sure exactly what your requirements are, especially the bit about ToList not doing what you need.
Unfortunately, BindingList<T> only accepts an IList<T> parameter in its constructor and not an IEnumerable<T>.
However, if you implement a pass-through constructor on your custom collection (or if it already has a constructor that takes IList<T>) then you could do something similar to this:
public class MyListObject<T> : BindingList<T>
{
public MyListObject() : base() { }
public MyListObject(IList<T> list) : base(list) { }
}
// ...
MyListObject<int> yourList = new MyListObject<int> { 1, 2, 3, 4, 5 };
yourList = new MyListObject<int>(yourList.Select(s => s * 2).ToList());
// yourList now contains 2, 4, 6, 8, 10
One option is to wrap the returned IEnumerable into your collection type by using/adding constructor that takes IEnumerable as CStick suggest. Perhaps a bit more ellegant way is to add an extension method for the IEnumerable type that would return your collection:
static MyListObject ToMyList(this IEnumerable<T> en) {
// construct your MyListObject from 'en' somehow
}
// And then just write:
var mylist = (from c in ... ).ToMyList()
The last option that's probably too complicated for this simple scenario is to implement all the LINQ query operators for your type (extension methods Where, Select, and many many others). The plus thing is that you could (maybe) do some things more efficiently, but it's really a bit difficult thing to do.
Most lists accept a range of objects in the constructor. Will that work?
Dim objects = 'Linq statement returning IEnumberable array.
Dim mlo As New MyListObject(objects)

Categories