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();
Related
I want to compare two lists and get the valid words into a new list.
var words = new List<string>();
var badWords = new List<string>();
//this is just an example list. actual list does contain 700 records
words.Add("Apple");
words.Add("Moron");
words.Add("Seafood");
words.Add("Cars");
words.Add("Chicken");
words.Add("Twat");
words.Add("Watch");
words.Add("Android");
words.Add("c-sharp");
words.Add("Fool");
badWords.Add("Idiot");
badWords.Add("Retarded");
badWords.Add("Twat");
badWords.Add("Fool");
badWords.Add("Moron");
I am looking for most efficient way to compare the lists and put all the 'good' words into a new list. The finalList shouldn't contain "Moron", "Twat" and "Fool".
var finalList = new List<string>();
Or is it unnecessary to create a new List? I am happy to hear your ideas!
Thank you in advance
Use EnumerableExcept function storing in System.Linq namespace
finalList = words.Except(badWords).ToList();
Most efficient way to save your time and also the fastest way to do it, because Except implementation uses Set, which is fast
Use Enumerable.Except:
List<string> cleanList = words.Except(badWords).ToList();
This is efficient because Except uses a set based approach.
An even more efficient approach is to avoid that "bad" words are added to the first list at all. For example by using a HashSet<string> with a case-insensitive comparer:
var badWords = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase){ "Idiot", "Retarded", "Twat", "Fool", "Moron" };
string word = "idiot";
if (!badWords.Contains(word))
words.Add(word);
https://msdn.microsoft.com/library/bb908822(v=vs.90).aspx
var words = new List<string>();
var badWords = new List<string>();
//this is just an example list. actual list does contain 700 records
words.Add("Apple");
words.Add("Moron");
words.Add("Seafood");
words.Add("Cars");
words.Add("Chicken");
words.Add("Twat");
words.Add("Watch");
words.Add("Android");
words.Add("c-sharp");
words.Add("Fool");
badWords.Add("Idiot");
badWords.Add("Retarded");
badWords.Add("Twat");
badWords.Add("Fool");
badWords.Add("Moron");
var result = words.Except(badWords).ToList();
Edit: Got in late.
you can use contains method
words.Where(g=>!badWords.Contains(g)).ToList()
If your don't want to create a new List you can remove the bad words from your existing List with RemoveAll()
words.RemoveAll(badWords.Contains);
I have a list of a custom type called Holdings. I am trying to query the list based on one property of the Holdings object to return a new list of Holdings. The LINQ query below does work correctly but I would like to replace var unitHld with List unitHld but can't get the code to work.
var unitHld = from hld in _holdingList
where hld.FundCode == lookThroList[i].FundCode
select new Holding() { Currency = hld.Currency,
FundCode = lookThroList[i].FundCode,
IdSedol = hld.IdSedol,
Nominal = hld.Nominal * unitWgt,
Price = hld.Price };
This new list is then slightly altered before being added back to the original list (I know the logic sounds strange but please accept this is how it has to be done). However because unitHld is var the line below does not work.
_holdingList.Add(unitHld);
The following call only adds a single item (where the item must be the same type as the list's elements):
_holdingList.Add(unitHld);
But you want to add a range of items, so do it like this:
_holdingList.AddRange(unitHld);
where unitHld is IEnumerable<T> and T is the type of the list's elements.
(This answer assumes that holdingList is of type List<T>, and that T is in fact Holding for your example.)
See List.AddRange() for details.
C# is statically typed.
var is not a type, all it does is a shortcut for in your case typing IEnumerable<Holding>.
If you want the result to be List<Holding> then all you need to do is wrap your query in brackets and put .ToList() at the end.
However, to append this to another list, you don't need to do that. Simply call .AddRange on the other list.
Alternatively, you can use Concat
var bothLists = aList.Concat(anotherList);
I would like to replace var unitHld with List unitHld but can't get the code to work.
You need to call ToList() on the result of the query:
var unitHld = from hld in _holdingList
where hld.FundCode == lookThroList[i].FundCode
select new Holding() { Currency = hld.Currency,
FundCode = lookThroList[i].FundCode,
IdSedol = hld.IdSedol,
Nominal = hld.Nominal * unitWgt,
Price = hld.Price };
List<Holding> unitHldList = unitHld.ToList();
This new list is then slightly altered before being added back to the original list
Once the data is in unitHldList, you can alter it as needed.
the line below does not work. _holdingList.Add(unitHld);
When you add the content of a collection to a List<T>, use AddRange method instead of Add:
_holdingList.AddRange(unitHldList);
Try this:
_holdingList.AddRange(unitHld);
I have an object that contains a list of child objects, each of which in turn contains a list of children, and so on. Using that first generation of children only, I want to combine all those lists as cleanly and cheaply as possible. I know I can do something like
public List<T> UnifiedListOfTChildren<T>()
{
List<T> newlist = new List<T>();
foreach (childThing in myChildren)
{
newlist = newlist.Concat<T>(childThing.TChildren);
}
return newlist;
}
but is there a more elegant, less expensive LINQ method I'm missing?
EDIT If you've landed at this question the same way I did and are new to SelectMany, I strongly recommend this visual explanation of how to use it. Comes up near the top in google results currently, but is worth skipping straight to.
var newList = myChildren.SelectMany(c => c.TChildren);
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));
I am using C# and targeting the .NET Framework 3.5. I'm looking for a small, succinct and efficient piece of code to copy all of the items in a ListBox to a List<String> (Generic List).
At the moment I have something similar to the below code:
List<String> myOtherList = new List<String>();
// Populate our colCriteria with the selected columns.
foreach (String strCol in lbMyListBox.Items)
{
myOtherList.Add(strCol);
}
Which works, of course, but I can't help but get the feeling that there must be a better way of doing this with some of the newer language features. I was thinking of something like the List.ConvertAll method but this only applies to Generic Lists and not ListBox.ObjectCollection collections.
A bit of LINQ should do it:-
var myOtherList = lbMyListBox.Items.Cast<String>().ToList();
Of course you can modify the Type parameter of the Cast to whatever type you have stored in the Items property.
The following will do it (using Linq):
List<string> list = lbMyListBox.Items.OfType<string>().ToList();
The OfType call will ensure that only items in the listbox's items that are strings are used.
Using Cast, if any of the the items are not strings, you will get an exception.
How about this:
List<string> myOtherList = (from l in lbMyListBox.Items.Cast<ListItem>() select l.Value).ToList();
What about:
myOtherList.AddRange(lbMyListBox.Items);
EDIT based on comments and DavidGouge's answer:
myOtherList.AddRange(lbMyListBox.Items.Select(item => ((ListItem)item).Value));
You don't need more. You get List of all values from Listbox
private static List<string> GetAllElements(ListBox chkList)
{
return chkList.Items.Cast<ListItem>().Select(x => x.Value).ToList<string>();
}