Replacing IEnumerable with List - c#

I have a basic doubt but I am not able to figure out myself.
I have a piece of code as follows:
List<string> List = new List<string>();
List.Add("A");
List.Add("B");
List.Add("sam);
List.Add("Sed");
IEnumerable<string> names = from n in List where (n.StartsWith("S")) select n;
Why does the above code asks for a explicit conversion if IEnumerable is replaced with concrete implementation i.e., List.
i.e., if I use :
List<string> names = from n in List where (n.StartsWith("S")) select n;
has a compiler error.
I could blindly use Ienumerable , but I want learn what is happening when I use List?

List<T> implements IEnumerable<T>. This means that every list is an enumerable. But the relation does not work the way around. IEnumerable<T> does not implement IList<T>. There are many enumerables that are not a list; Stack<T>, HashSet<T>, arrays, Dictionary<T, K>, iterator blocks, etc.
You therefore have to explicitly create a list from the enumerable using the ToList() extensión method:
List<string> names = (from n in List where (n.StartsWith("S")) select n).ToList();

There is no implicit cast from IEnumerable<T> to List<T>, since IEnumerable is simply not a List.
If you want to convert your enumerable to list, use .ToList<T>():
List<string> names = (from n in List where (n.StartsWith("S")) select n).ToList();
Actually, your collection is even not enumerated until you call .ToList().

List is IEnumerable, IEnumerable is not List
In theory, in case of linq your expression is err an expression, not a collection. Collection usually has a finite number of elements whereas expression is just a function to select elements from some collection by specified rules.
By writing
var expression = from n in orig_collection select n;
you define an expression(IEnumerable) describing rules that will be applied on enumeration of orig_collection
By writing
var collection = expression.ToList();
you enumerate through orig_collection to the end applying expression in process. That will result with a new List

Related

IList does not contain a definition <linq function>

I have a IList
IList list = GetList();
and want to use Linq function on it like FirstOrDefault() or Where() but it says:
IList does not contain a definition for [linq function]
What am I doing wrong?
If your collection does not implement the generic interfaces you can use the Cast or OfType(Cast + Filter) extension methods.
IList list = GetList();
string first = list.Cast<string>().FirstOrDefault();
You can use these methods with anything that implements IEnumerable. Of course it works only if the list really contains strings. If it could contain anything you could use:
string first = list.Cast<Object>().Select(obj => obj?.ToString() ?? "").FirstOrDefault();
If you just want objects that are strings you can use OfType as mentioned above:
string first = list.OfType<string>().FirstOrDefault();
Make sure you are using the generic IList with the type you use like this
IList<string> list = GetList();
Then you can use LINQ functions on that list.

Ordering xamarin forms observable collection

In xamarin forms do I have a Oberservable collection of wordpress posts.
I want to sort this collection by a specific value within this collection?
How am I able to do so in Xamarin forms / c# ?
I can see somewhere are people using:
list.OrderByDescending(x => DateTime.Parse(x)).ToList();
But this does not use a Observable collection or a specific value from this collection to sort.
The fill of my object is this:
FlowObservableCollection<RootObject2> result = JsonConvert.DeserializeObject<FlowObservableCollection<RootObject2>>(await posts.Content.ReadAsStringAsync());
Does anyone have a solution for sorting my array?
My value I wanna sort by is a sub value like: mycollection.group.Myvalue
Thanks in advance!
I am not familiar with FlowObservableCollection<T> but from what I could find it seems to be a subtype of ObservableCollection<T>Microsoft Docs.
Since ObservableCollection<T> itself is a subtype of Collection<T> and therefore implements IEnumerable<T> you should not have any problem using its extension methods, e.g. OrderBy.
I can see somewhere are people using:
list.OrderByDescending(x => DateTime.Parse(x)).ToList();
My value I wanna sort by is a sub value like: mycollection.group.Myvalue
Are you familiar with lambda expressions as used in the LINQ query of your OrderByDescending() example?
In case your not, in list.OrderByDescending(x => DateTime.Parse(x)).ToList(); the term x refers to an element in the list and what your specify to the right of the => arrow is your key for ordering.
So if you wanto to order by a different value you could simply write something like myCollection.OrderByDescending(x => x.MyProperty); Note that you can use terms different from x as long as they are the same on both sides of the arrow, e.g. myCollection.OrderByDescending(myElement => myElement.MyProperty);
Finally note that the call to myCollection.OrderByDescending() returns a new IEnumerable with the elements found in myCollection and does not change myCollection itself.
You cannot cast IEnumerable<T> to FlowObservableCollection<T>. So if you need an ordered FlowObservableCollection<T> you have to instantiate a new one using your ordered IEnumerable as an input.
In your case this is what it might look like:
var orderedElements = myCollection.OrderByDescending(x => x.MyProperty);
var orderedCollection = new FlowObservableCollection<RootObject2>(orderedElements);`
You can try this:
Collection = new ObservableCollection(Collection.OrderBy(x=>x.Date).ToList());
Or adapt this method:
public static void Sort<T>(this ObservableCollection<T> collection, Comparison<T> comparison)
{
var sortableList = new List<T>(collection);
sortableList.Sort(comparison);
for (int i = 0; i < sortableList.Count; i++)
{
collection.Move(collection.IndexOf(sortableList[i]), i);
}
}

Intersect two List<> in C#

I have two List<T> objects that I would like to intersect, but I get errors when trying.
// Make the Keys in the Dictionary<Load, double> _loads to form a List<Load>
List<Load> l1 = _loads.Keys.ToList();
// Get a list from my element.
List<Load> l2 = element.ListLoads;
// Intersect
List<Load> loads = (List<Load>)l1.Intersect<Load>(l2);
Intersect<T> returns an IEnumerable<T>, so the correct way is:
var loads = l1.Intersect(l2).ToList();
ToList<T> creates a List<T> from an IEnumerable<T>.
Note that you can omit the type argument when invoking Intersect<T>, the compiler is smart enough to infer it.
You can do it this way:
List<Load> loads=new List<Load>(l1.Intersect(l2));
This is because Intersect will return an IEnumerable and this is the right way to create a new list from an IEnumerable.

Remove item from List<T>

List<object> A = new List<object>;
List<object> B = new List<object>;
List<object> C = new List<object>;
C.Add(item);
B.Add(C);
A.Add(B);
Finally I have List A than contains List B and List B contains List C.
I want to remove a item from list C.
How can I do this with LINQ or lambda?
LINQ is not intended to be used for in-place changes to collections. Use old-school Remove / RemoveAll:
((List<object>)((List<object>)A[0])[0]).Remove(item);
((List<object>)((List<object>)A[0])[0]).RemoveAll(o => ((MyClass)o).Id == 5);
Note: the number of casts required in this code snippet indicates that your way of using List<T> may not be optimal for your use case. I strongly recommend you think about specifying a more specific generic argument than object.
Have a look at Remove, RemoveAt and RemoveRange.

How can I add an item to a IEnumerable<T> collection?

My question as title above. For example
IEnumerable<T> items = new T[]{new T("msg")};
items.ToList().Add(new T("msg2"));
but after all it only has 1 item inside. Can we have a method like items.Add(item) like the List<T>?
You cannot, because IEnumerable<T> does not necessarily represent a collection to which items can be added. In fact, it does not necessarily represent a collection at all! For example:
IEnumerable<string> ReadLines()
{
string s;
do
{
s = Console.ReadLine();
yield return s;
} while (!string.IsNullOrEmpty(s));
}
IEnumerable<string> lines = ReadLines();
lines.Add("foo") // so what is this supposed to do??
What you can do, however, is create a new IEnumerable object (of unspecified type), which, when enumerated, will provide all items of the old one, plus some of your own. You use Enumerable.Concat for that:
items = items.Concat(new[] { "foo" });
This will not change the array object (you cannot insert items into to arrays, anyway). But it will create a new object that will list all items in the array, and then "Foo". Furthermore, that new object will keep track of changes in the array (i.e. whenever you enumerate it, you'll see the current values of items).
The type IEnumerable<T> does not support such operations. The purpose of the IEnumerable<T> interface is to allow a consumer to view the contents of a collection. Not to modify the values.
When you do operations like .ToList().Add() you are creating a new List<T> and adding a value to that list. It has no connection to the original list.
What you can do is use the Add extension method to create a new IEnumerable<T> with the added value.
items = items.Add("msg2");
Even in this case it won't modify the original IEnumerable<T> object. This can be verified by holding a reference to it. For example
var items = new string[]{"foo"};
var temp = items;
items = items.Add("bar");
After this set of operations the variable temp will still only reference an enumerable with a single element "foo" in the set of values while items will reference a different enumerable with values "foo" and "bar".
EDIT
I contstantly forget that Add is not a typical extension method on IEnumerable<T> because it's one of the first ones that I end up defining. Here it is
public static IEnumerable<T> Add<T>(this IEnumerable<T> e, T value) {
foreach ( var cur in e) {
yield return cur;
}
yield return value;
}
Have you considered using ICollection<T> or IList<T> interfaces instead, they exist for the very reason that you want to have an Add method on an IEnumerable<T>.
IEnumerable<T> is used to 'mark' a type as being...well, enumerable or just a sequence of items without necessarily making any guarantees of whether the real underlying object supports adding/removing of items. Also remember that these interfaces implement IEnumerable<T> so you get all the extensions methods that you get with IEnumerable<T> as well.
In .net Core, there is a method Enumerable.Append that does exactly that.
The source code of the method is available on GitHub..... The implementation (more sophisticated than the suggestions in other answers) is worth a look :).
A couple short, sweet extension methods on IEnumerable and IEnumerable<T> do it for me:
public static IEnumerable Append(this IEnumerable first, params object[] second)
{
return first.OfType<object>().Concat(second);
}
public static IEnumerable<T> Append<T>(this IEnumerable<T> first, params T[] second)
{
return first.Concat(second);
}
public static IEnumerable Prepend(this IEnumerable first, params object[] second)
{
return second.Concat(first.OfType<object>());
}
public static IEnumerable<T> Prepend<T>(this IEnumerable<T> first, params T[] second)
{
return second.Concat(first);
}
Elegant (well, except for the non-generic versions). Too bad these methods are not in the BCL.
No, the IEnumerable doesn't support adding items to it. The alternative solution is
var myList = new List(items);
myList.Add(otherItem);
To add second message you need to -
IEnumerable<T> items = new T[]{new T("msg")};
items = items.Concat(new[] {new T("msg2")})
I just come here to say that, aside from Enumerable.Concat extension method, there seems to be another method named Enumerable.Append in .NET Core 1.1.1. The latter allows you to concatenate a single item to an existing sequence. So Aamol's answer can also be written as
IEnumerable<T> items = new T[]{new T("msg")};
items = items.Append(new T("msg2"));
Still, please note that this function will not change the input sequence, it just return a wrapper that put the given sequence and the appended item together.
Not only can you not add items like you state, but if you add an item to a List<T> (or pretty much any other non-read only collection) that you have an existing enumerator for, the enumerator is invalidated (throws InvalidOperationException from then on).
If you are aggregating results from some type of data query, you can use the Concat extension method:
Edit: I originally used the Union extension in the example, which is not really correct. My application uses it extensively to make sure overlapping queries don't duplicate results.
IEnumerable<T> itemsA = ...;
IEnumerable<T> itemsB = ...;
IEnumerable<T> itemsC = ...;
return itemsA.Concat(itemsB).Concat(itemsC);
Others have already given great explanations regarding why you can not (and should not!) be able to add items to an IEnumerable. I will only add that if you are looking to continue coding to an interface that represents a collection and want an add method, you should code to ICollection or IList. As an added bonanza, these interfaces implement IEnumerable.
you can do this.
//Create IEnumerable
IEnumerable<T> items = new T[]{new T("msg")};
//Convert to list.
List<T> list = items.ToList();
//Add new item to list.
list.add(new T("msg2"));
//Cast list to IEnumerable
items = (IEnumerable<T>)items;
Easyest way to do that is simply
IEnumerable<T> items = new T[]{new T("msg")};
List<string> itemsList = new List<string>();
itemsList.AddRange(items.Select(y => y.ToString()));
itemsList.Add("msg2");
Then you can return list as IEnumerable also because it implements IEnumerable interface
Instances implementing IEnumerable and IEnumerator (returned from IEnumerable) don't have any APIs that allow altering collection, the interface give read-only APIs.
The 2 ways to actually alter the collection:
If the instance happens to be some collection with write API (e.g. List) you can try casting to this type:
IList<string> list = enumerableInstance as IList<string>;
Create a list from IEnumerable (e.g. via LINQ extension method toList():
var list = enumerableInstance.toList();
IEnumerable items = Enumerable.Empty(T);
List somevalues = new List();
items.ToList().Add(someValues);
items.ToList().AddRange(someValues);
Sorry for reviving really old question but as it is listed among first google search results I assume that some people keep landing here.
Among a lot of answers, some of them really valuable and well explained, I would like to add a different point of vue as, to me, the problem has not be well identified.
You are declaring a variable which stores data, you need it to be able to change by adding items to it ? So you shouldn't use declare it as IEnumerable.
As proposed by #NightOwl888
For this example, just declare IList instead of IEnumerable: IList items = new T[]{new T("msg")}; items.Add(new T("msg2"));
Trying to bypass the declared interface limitations only shows that you made the wrong choice.
Beyond this, all methods that are proposed to implement things that already exists in other implementations should be deconsidered.
Classes and interfaces that let you add items already exists. Why always recreate things that are already done elsewhere ?
This kind of consideration is a goal of abstracting variables capabilities within interfaces.
TL;DR : IMO these are cleanest ways to do what you need :
// 1st choice : Changing declaration
IList<T> variable = new T[] { };
variable.Add(new T());
// 2nd choice : Changing instantiation, letting the framework taking care of declaration
var variable = new List<T> { };
variable.Add(new T());
When you'll need to use variable as an IEnumerable, you'll be able to. When you'll need to use it as an array, you'll be able to call 'ToArray()', it really always should be that simple. No extension method needed, casts only when really needed, ability to use LinQ on your variable, etc ...
Stop doing weird and/or complex things because you only made a mistake when declaring/instantiating.
Maybe I'm too late but I hope it helps anyone in the future.
You can use the insert function to add an item at a specific index.
list.insert(0, item);
Sure, you can (I am leaving your T-business aside):
public IEnumerable<string> tryAdd(IEnumerable<string> items)
{
List<string> list = items.ToList();
string obj = "";
list.Add(obj);
return list.Select(i => i);
}

Categories