I have looked this up on the net but I am asking this to make sure I haven't missed out on something. Is there a built-in function to convert HashSets to Lists in C#? I need to avoid duplicity of elements but I need to return a List.
Here's how I would do it:
using System.Linq;
HashSet<int> hset = new HashSet<int>();
hset.Add(10);
List<int> hList= hset.ToList();
HashSet is, by definition, containing no duplicates. So there is no need for Distinct.
Two equivalent options:
HashSet<string> stringSet = new HashSet<string> { "a", "b", "c" };
// LINQ's ToList extension method
List<string> stringList1 = stringSet.ToList();
// Or just a constructor
List<string> stringList2 = new List<string>(stringSet);
Personally I'd prefer calling ToList is it means you don't need to restate the type of the list.
Contrary to my previous thoughts, both ways allow covariance to be easily expressed in C# 4:
HashSet<Banana> bananas = new HashSet<Banana>();
List<Fruit> fruit1 = bananas.ToList<Fruit>();
List<Fruit> fruit2 = new List<Fruit>(bananas);
List<ListItemType> = new List<ListItemType>(hashSetCollection);
There is the Linq extension method ToList<T>() which will do that (It is defined on IEnumerable<T> which is implemented by HashSet<T>).
Just make sure you are using System.Linq;
As you are obviously aware the HashSet will ensure you have no duplicates, and this function will allow you to return it as an IList<T>.
Related
I have multiple functions that returns a List of objects. How can I add them into one list.
var List1 = GetList1().RunFilter1();
var List2 = GetList2();
The AddRange() function gets far to messy.
List1.AddRange(List2.AddRange(List3.AddRange(List4.AddRange(...);
Is there a pattern that I can use that it will be easier. I also have extension methods (Filters) that apply to certain lists. Which I interchange based on requirement.
Something like this:
var CombinedList = GetAllLists(GetList1().RunFilter1(),
GetList2(),
GetList3().RunFilter2(),
GetList4() ...);
Keep in mind that the GetList() functions being fetched might change.
Thanks for any help!
You can use some Linq extensions to help you out with the format a bit
var joined = GetList1()
.Concat(GetList2())
.Concat(GetList3().RunFilter())
...
;
You could first insert all your lists into another list:
var temp = new List<T>
{
GetList1().RunFilter1(),
GetList2(),
GetList3().RunFilter2(),
GetList4()
};
Then using the SelectMany method flatten this list.
var combined = temp.SelectMany(item=>item).ToList();
I have two string arrays
string[] a = ...
string[] b = ...
I want to remove any items from a that also exist in b or return a new array with only those items that exist only in a.
So, for example, if
a={"a", "b", "c"};
and,
b={"b"}
then the result should be
{"a", "c"}
Is there a neat lambda expression or Linq or something I can use to do this?
Thanks,
Sachin
I believe Except will do what you want. Remember, Except, like most LINQ Extension methods, will not modify the existing collection. It will return a new collection.
c = a.Except(b)
It's been a while since I've used lambda expressions or LINQ and am wondering how I would do the following (I know I can use a foreach loop, this is just out of curiosity) using both methods.
I have an array of string paths (does it make a difference if it's an array or list here?) from which I want to return a new list of just the filenames.
i.e. using a foreach loop it would be:
string[] paths = getPaths();
List<string> listToReturn = new List<string>();
foreach (string path in paths)
{
listToReturn.add(Path.GetFileName(path));
}
return listToReturn;
How would I do the same thing with both lambda and LINQ?
EDIT: In my case, I'm using the returned list as an ItemsSource for a ListBox (WPF) so I'm assuming it's going to need to be a list as opposed to an IEnumerable?
Your main tool would be the .Select() method.
string[] paths = getPaths();
var fileNames = paths.Select(p => Path.GetFileName(p));
does it make a difference if it's an array or list here?
No, an array also implements IEnumerable<T>
Note that this minimal approach involves deferred execution, meaning that fileNames is an IEnumerable<string> and only starts iterating over the source array when you get elements from it.
If you want a List (to be safe), use
string[] paths = getPaths();
var fileNames = paths.Select(p => Path.GetFileName(p)).ToList();
But when there are many files you might want to go the opposite direction (get the results interleaved, faster) by also using a deferred execution source:
var filePaths = Directory.EnumerateFiles(...); // requires Fx4
var fileNames = filePaths.Select(p => Path.GetFileName(p));
It depends on what you want to do next with fileNames.
I think by "LINQ" you really mean "a query expression" but:
// Query expression
var listToReturn = (from path in paths
select Path.GetFileName(path)).ToList();
// Extension methods and a lambda
var listToReturn = paths.Select(path => Path.GetFileName(path))
.ToList();
// Extension methods and a method group conversion
var listToReturn = paths.Select(Path.GetFileName)
.ToList();
Note how the last one works by constructing the projection delegate from a method group, like this:
Func<string, string> projection = Path.GetFileName;
var listToReturn = paths.Select(projection).ToList();
(Just in case that wasn't clear.)
Note that if you don't need to use this as a list - if you just want to iterate over it, in other words - you can drop the ToList() call from each of these approaches.
It's just:
var listToReturn = getPaths().Select(x => Path.GetFileName(x)).ToList();
As already stated in other answers, if you don't actually need a List<string> you can omit the ToList() and simply return IEnumerable<string> (for example if you just need to iterate it, IEnumerable<> is better because avoids the creation of an other list of strings)
Also, given that Select() method takes a delegate, and there's an implicit conversion between method groups and delegates having the same signature, you can skip the lambda and just do:
getPaths().Select(Path.GetFileName)
You could do it like this:
return getPaths().Select(Path.GetFileName);
listToReturn = paths.ToList().Select(p => Path.GetFileName(p));
How do I go about converting a reflection.propertyinfo[] to a generic.list<>?
One of the List<T> constructors accepts an IEnumerable<T> as its argument (i.e., your PropertyInfo array):
var list = new List<PropertyInfo>( propInfoArray );
var list = yourArray.ToList();
Try using .ToList()
http://msdn.microsoft.com/en-us/library/bb342261.aspx
All of the above are correct. But it should also be mentioned that, like List<T> all .net arrays implement IList<T>.
var IList<PropertyInfo> ilist = reflection.propertyinfo;
Since I know that, almost all my functions accept IList<T> when I need a list-like collection, which I can use with traditional arrays and lists.
Use the extension method ToList() available in the System.Linq namespace:
var myProperties = propertyInfoArray.ToList();
Why do i receive error in the following declaration ?
List<int> intrs = new List<int>().AddRange(new int[]{1,2,3,45});
Error :Can not convert type void to List ?
Because AddRange function does not return a value. You might need to perform this in two steps:
List<int> intrs = new List<int>();
intrs.AddRange(new int[]{1,2,3,45});
You could also use a collection initializer (assuming C# 3.0+).
List<int> intrs = new List<int> { 1, 2, 3, 45 };
Edit by 280Z28: This works for anything with an Add method. The constructor parenthesis are optional - if you want to pass thing to a constructor such as the capacity, you can do so with List<int>(capacity) instead of just List<int> written above.
Here's an MSDN reference for details on the Object and Collection Initializers.
Dictionary<string, string> map = new Dictionary<string, string>()
{
{ "a", "first" },
{ "b", "second" }
};
Because AddRange modifies the specified list instead of returning a new list with the added items. To indicate this, it returns void.
Try this:
List<int> intrs = new List<int>();
intrs.AddRange(new int[]{1,2,3,45});
If you want to create a new list without modifying the original list, you can use LINQ:
List<int> intrs = new List<int>();
List<int> newIntrs = intrs.Union(new int[]{1,2,3,45}).ToList();
// intrs is unchanged
AddRange does not return the list it has added items to (unlike StringBuilder). You need to do something like this:
List<int> intrs = new List<int>();
intrs.AddRange(new int[]{1,2,3,45});
AddRange() is declared as:
public void AddRange(object[]);
It does not return the list.
By the way in C# 3.x (not sure about 2.0) you can do either of
List<int> intrs = new List<int>{1,2,3,45};
List<int> intrs = new []{1,2,3,45}.ToList(); // with Linq extensions
Besides other answers, you can add your own extension method that will add range and return list (not that it's a good practice).
BTW, if you had already declared intrs, you could have done it with parentheses:
(intrs = new List<int>()).AddRange(new int[] { 1, 2, 3, 45 });
However, I like the initialization syntax better.
Although others have already mentioned that AddRange does not return a value, based on the samples given for alternatives it should also be remembered that the constructor of List will take an IEnumerable of T as well in addition to the code previously mentioned that is .NET 3.5+
For example:
List<int> intrs = new List<int>(new int[]{2,3,5,7});
There is yet another way.
List<int> intrs = new List<int>
{
1,
2,
3,
45
};