Convert IEnumerable to List<string> in .net 2.0 - c#

I need to convert IEnumerable to a List<string>. one of the way is to itearte through this and add each object to a list but this process is vary time consuming. Is there any other way to do this. Any help would be appreciated.

You can pass the enumerable directly into the constructor of a new List<string> instace:
List<string> list = new List<string>(yourEnumerable);
or you can use the AddRange method:
List<string> list = new List<string>();
list.AddRange(yourEnumerable);
This answer assumes that you in fact already have an IEnumerable<string>.
If this is not the case, your only option is a loop:
List<string> list = new List<string>();
foreach(object item in yourEnumerable)
list.Add(item.ToString());
BTW: You are saying:
one of the way is to itearte through this and add each object to a list but this process is vary time consuming
You need to iterate the enumerable in any case. How else would you get all values? In the first two sample codes I gave you, the enumeration is performed inside the List<T> class, but it is still happening.

Related

Create ArrayList in one step

I'm desperately trying to create an ArrayList out of objects of an enumeration in one step in C# with Visual Studio 2012.
It should look like something of the following:
new ArrayList( {class1.enum.sample1, class1.enum.sample2, class1.enum.sample3} );
When I'm writing it in two lines, it works:
class1.enum[] array = {class1.enum.sample1, class1.enum.sample2, class1.enum.sample3};
ArrayList test = new ArrayList(ha);
But I need to write it in one line. Could you help me, please?
You need another collection like an array to be able to use the collection initializer:
var al = new ArrayList { new[] { class1.enum.sample1, class1.enum.sample2, class1.enum.sample3 } };
But there is no reason to use the old ArrayList anymore. In this case you could use a List<class1.enum> (apart from the fact that enum is a keyword).
You do not need parenthesis () for array list initializer. You can initialize in a single line as under.
ArrayList test = new ArrayList{class1.enum.sample1, class1.enum.sample2, class1.enum.sample3}
Array list should be replace with generic list unless you have solid reason to use Arraylist. You can find more about using generic list in Benefits of Generics on MSDN

Add a List<object> or Arraylist to an array of CustomObject[]

I have tried many ways like
Cast<CustomObject>, as Customobject and ToArray(Customobject) but nothing worked.
How can I add List or ArrayList via AddRange to a CustomObject[] Array?
Code is really difficult.
But if you have some time you can get the complete source of the destination list from here:
http://www.codeproject.com/Articles/4012/C-List-View-v1-3?msg=3844172#xx3844172xx
This is a Custom Listview
I activated a combobox for the second column, so I can select diferrent values for a cell.
But before this, I have to add something to select.
This is the hole problem.
Update:
Firstly, thanks for the help !
Secondly, Found a solution in the comments from the website with the source.
Had to add some code and changed the destination custom array to a List
list.Cast<CustomObject>().ToArray()
Will work as long as the things in the list are actually CustomObject. If they might be other types, you can use OfType<CustomObject>() instead of Cast. This will filter out anything of an incompatible type.
Assuming the objects really are instances of CustomObject, use LINQ Select method:
objList.Select(o => o as CustomObject).ToArray();
Otherwise you will get an array of null.
If its a List<CustomObject> then let us say
CustomObject[] coarr = list_of_customobject.ToArray();
If its an ArrayList then
CustomObject[] coarr = arraylist.OfType<CustomObject>().ToArray();
If you are unsure whether all of your objects are of the type CustomObject try
var result = list.OfType<CustomObject>.ToArray();
Strictly speaking you cannot add elements to an array, since an array's length remains constant over its lifetime. There are two things you can do:
Create a new array
myArray = myTList.ToArray() // generic)
myArray = myArrayList.Cast<CustomObject>().ToArray() // cast, non-generic
myArray = myArrayList.OfType<CustomObject>().ToArray() // filter by type, non-generic
Set elements of an array
myArray[x] = myTList[y] // generic
myArray[x] = (CustomObject)myArrayList[y] // non-generic
I recommend you to take the generic collection whenever possible. They provide you additional type safety. Casting object variables cause runtime errors you could detect at compile time by using generic types.
If you actually want to add elements to an existing collection, you may try to use a dynamic collection type rather than an array: List<T> : IList<T> or LinkedList<T> : ICollection<T> are a good point to start, or maybe more specific types like Stack<T> or Queue<T>.

OrderBy and List vs. IOrderedEnumerable

I ran across an unexpected problem with the following code.
List<string> items = new List<string>();
items = items.OrderBy(item => item);
This code generates the error:
Cannot implicitly convert type 'System.Linq.IOrderedEnumerable' to 'System.Collections.Generic.List'. An explicit conversion exists (are you missing a cast?)
It appears I can change items to be of type IEnumerable<string> and the error goes away. But I need to be able to add items to the list, which IEnumerable doesn't support.
Can someone help me understand this error, and what the easiest fix is? Is it safe to simply cast the result?
Why not just sort the list in place using the Sort() instance method; then you can add items to it later if you like:
List<string> items = GetSomeItems();
items.Sort();
Or, use an ordered collection like a binary search tree. SortedSet<T> might fit the bill, depending on your needs.
The solution suggested by the others:
items = items.OrderBy(item => item).ToList();
... creates another list with the original items in a new order. This is only useful if you need to preserve the original ordering for some other purpose; it's rather more wasteful of memory than sorting the list in place.
As far as understanding the error, it's simple: List<T> isn't a subtype of IOrderedEnumerable<T>, so there's no implicit reference conversion between the two. The explicit cast that the compiler suggests will satisfy the compiler, but it will fail at run time because the object returned by OrderBy<T> does not inherit from List<T>.
EDIT
An example of List<T>.Sort(Comparison<T>), assuming the type MyType has a Key property of some type type T where T : IComparable<T>:
List<MyType> items = GetSomeItems();
items.Sort((a, b) => a.Key.CompareTo(b.Key));
You need to convert the IEnumerable to a List. Try this:
items = items.OrderBy(item => item).ToList();
You need to use LINQ's ToList() method
items = items.OrderBy(item => item).ToList();
You can't cast directly from IEnumerable<> to List<>
Try this
items = items.OrderBy(item => item).ToList();
For sorting a list of strings you do not need Linq in the first place - just use Sort():
List<string> items = new List<string>();
//add items here
items.Sort();
OrderBy() is an extension method of IEnumerable - and not List.
When the compiler encounters the OrderBy() extension method, it casts the range variable to an IOrderedEnumerable where it can perform the required sorting via CreateOrderedEnumerable method using IComparer et al. Once sorted, the compiler spits out the variable as IEnumerable - usually.
Suggestion: use the var keyword to type 'items' in the LinQ clause.
Certainly the options offered above using the Sort() and ToList() methods will work - however, using them involves greedy operators and you lose the advantage of lazy loading.
Here's a good breakdown here:
C# Sort and OrderBy comparison between running Sort() and OrderBy().

c# Find an item in 2 / multiple lists

I have the presumably common problem of having elements that I wish to place in 2 (or more) lists. However sometimes I want to find an element that could be in one of the lists. Now there is more than one way of doing this eg using linq or appending, but all seem to involve the unnecessary creation of an extra list containing all the elements of the separate lists and hence waste processing time.
So I was considering creating my own generic FindinLists class which would take 2 lists as its constructor parameters would provide a Find() and an Exists() methods. The Find and Exists methods would only need to search the second or subsequent lists if the item was not found in the first list. The FindInLists class could be instantiated in the getter of a ( no setter)property. A second constructor for the FindInLists class could take an array of lists as its parameter.
Is this useful or is there already a way to search multiple lists without incurring the wasteful overhead of the creation of a super list?
You could use the LINQ Concat function.
var query = list1.Concat(list2).Where(x => x.Category=="my category");
Linq already has this functionality by virtue of the FirstOrDefault method. It uses deferred execution so will stream from any input and will short circuit the return when a matching element is found.
var matched = list1.Concat(list2).FirstOrDefault(e => element.Equals(e));
Update
BaseType matched = list1.Concat(list2).Concat(list3).FirstOrDefault(e => element.Equals(e));
I believe IEnumerable<T>.Concat() is what you need. It doesn't create an extra list, it only iterates through the given pair of collections when queried
Concat() uses deferred execution, so at the time it's called it only creates an iterator which stores the reference to both concatenated IEnumerables. At the time the resulting collection is enumerated, it iterates through first and then through the second.
Here's the decompiled code for the iterator - no rocket science going on there:
private static IEnumerable<TSource> ConcatIterator<TSource>(IEnumerable<TSource> first, IEnumerable<TSource> second)
{
foreach (TSource iteratorVariable0 in first)
{
yield return iteratorVariable0;
}
foreach (TSource iteratorVariable1 in second)
{
yield return iteratorVariable1;
}
}
When looking to the docs for Concat(), I've stumbled across another alternative I didn't know - SelectMany. Given a collection of collections it allows you to work with the children of all parent collections at once like this:
IEnumerable<string> concatenated = new[] { firstColl, secondColl }
.SelectMany(item => item);
you can do something like this:
var list1 = new List<int>{1,2,3,4,5,6,7};
var list2 = new List<int>{0,-3,-4,2};
int elementToPush = 4;//value to find among available lists
var exist = list1.Exists(i=>i==elementToPush) || list2.Exists(j=>j==elementToPush);
If at least one collection required element exists, result is false, otherwise it's true.
One row and no external storage creation.
Hope this helps.
You could probably just create a List of lists and then use linq on that list. It is still creating a new List but it is a list of references rather than duplicating the contents of all the lists.
List<string> a = new List<string>{"apple", "aardvark"};
List<string> b = new List<string>{"banana", "bananananana", "bat"};
List<string> c = new List<string>{"cat", "canary"};
List<string> d = new List<string>{"dog", "decision"};
List<List<string>> super = new List<List<string>> {a,b,c,d};
super.Any(x=>x.Contains("apple"));
the Any call should return after the first list returns true so as requested will not process later lists if it finds it in an earlier list.
Edit: Having written this I prefer the answers using Concat but I leave this here as an alternative if you want something that might be more aesthetically pleasing. ;-)

Is this "listMerging" code improvable?

I have a method who merge two lists. The two merged lists are lists of subtypes objects of the returned list. By "merging" I mean "Allowing duplicates".
So Sub1 and Sub2 types are subtypes from Sup1 type.
Here is my code
var listSub1 = new List<Sub1>(); //With some content added..
var listSub2 = new List<Sub2>(); //With content too..
var listToReturn = new List<Sup1>();
listToReturn.AddRange(listSub1.Select(item => item as Sup1).ToList());
listToReturn.AddRange(listSub2.Select(item => item as Sup1).ToList());
return listeToReturn;
It is working fine but I wonder if it is the best way to merge and cast the lists.
you could write
var newList =
listSub1.Cast<Sup1>()
.Concat(listSub2.Cast<Sup1>()).ToList();
Note that Union is not correct to be used, since it will make sure that objects that are "equal" will come out only once.
return listSub1.Cast<Sup1>().Concat(list2.Cast<Sup1>()).ToList()
var result = listSub1.AddRang(listSub2 ).Cast<Sup1>().ToList()
Why not just use LINQ's Union? That should to the trick.
Assuming I don't have to keep binary compatibility with an older released version, I'd redefine the return type as IEnumerable<Sub1> and code it as:
return listSub1.Concat(listSub2);
If a caller really needs a list, it can call .ToList() itself, but a caller that doesn't need a list (e.g. it's just going to foreach through it all) needn't suffer the delay and memory use of .ToList().
Using .ToList() only when needed is a micro-opt as a single change, but as a coding habit can begin to add up significantly.
you can do with linq:
var listToReturn = listSub1.Cast<Sup1>().Concat(listSub2).ToList();
edit: to match the edited question

Categories