How to Union List<List<String>> in C# - c#

I'm having a List<List<String>>, and which contains
{ {"A" , "B" },
{"C" , "D" }
}
I need to union all the innerlist into another list
So the resulting List<String> will contain
{"A","B","C","D"}
Now im using for loop to do this
Is there any way to do this Using LINQ or Lambda Expression.
Please help me to do this.
Thanks in advance.

Not Exactly a Union, but you can try this
YourList.SelectMany(l=>l).Distinct()

List<List<string>> collections = new List<List<string>>()
{
new List<string>(){"A" , "B" },
new List<string>() {"C" , "D" }
};
var list = collections.SelectMany(x => x).ToList();
SelectMany builds up a expression tree that when evaluated flattens the list of list to a single list of combined members.
ToList forces the expression tree to be evaluated and which results in a List.
If you want to eliminate duplicates you can add a Distinct call before the call to 'ToList()'

You can use the SelectMany extension method.
List<List<String>> masterList = { {"A" , "B" }, {"C" , "D" } };
IEnumerable<string> results = masterList.SelectMany(l => l);

var result = myLists.SelectMany(l => l);

How about Aggregate?
myLists.Aggregate((left, right) => left.Union(right));
To me, this is more expressive than using SelectMany, because it is telling you exactly what you are doing: Aggregate your list of lists by calling union on them all.

Just for kicks:
(from list in theList from e in list select e).Distinct().ToList()
This is of course the same solution as #Alexander Taran's, just with query syntax instead of lambda syntax. (Or at least it should be – I don't have my LINQPad handy.)

Related

Should AddRange() return a list

In the following code:
var cats = new List<string>() {"cat1", "cat2"};
var dogs = new List<string>() {"dog1", "dog2"};
var animals = new List<Animal>();
animals = (cats.Select(x => new Animal() {Type = "Cat", Name = x}).ToList().AddRange(
dogs.Select(x => new Animal() {Type = "Dog", Name = x}).ToList())).ToList();
Calling the ToList() at the end is an error, because AddRange() returns void. This doesn't seem right nowadays when using Linq type queries.
I found I could change it to .Union() or .Concat() to fix the issue, but shouldn't AddRange() be updated, or is there a reason for it returning void?
AddRange changes the underlying List object. No LinQ method does that. So it's fundamentally different and should not be used in a LinQ concatination. It's return value of void reflects that.
You've answered your own question. If you want distinct values from the two lists use Union, if you want to just join the two lists use Concat. Once the two enumerable have been joined you can call ToList().
AddRange is a method on the List its self and isn't anything to do with LINQ.
AddRange is a method on List<T> that pre-dates LINQ. It mutates the current list in situ and so doesn't need to return it (nor does it follow the fluent syntax style you find a lot these days). List<T> is not immutable, so mutating method calls are fine.
There are linq methods that can join lists together (as you've noted in the question). I would tend to not have mutating actions embedded in a linq method chain as it goes against the general idea that linq is just a query / projection set-up and doesn't "update" things.
In your case, it is better to use Enumerable.Concat:
animals = cats.Select(x => new Animal() {Type = "Cat", Name = x})
.Concat(dogs.Select(x => new Animal() {Type = "Dog", Name = x})).ToList();

add results to linq query

I'm querying a datatable using linq, I then query the results to filter out what I want, the problem is that I need to query it for each value of an array these values are like this ,2, or ,22, or ,21, etc
so I usually do this
results = from a in results
where a.countryId.ToString().Contains(value)
select a;
what I would like to do is this
foreach(string str in arrayval)
{
results += from a in results
where a.countryId.ToString().Contains(str)
}
can anyone help or give me some clues
thanks
Looks like you want to select results based on comparison from the array values. Something like. Select * from table where ID in (1,2,3). Instead of concatenating results you can try the following query.
var result = from a in result
where arrayval.Contains(a.CountryId.ToString())
select a;
if your arrayval is an int type array then you may remove .ToString() at the end of a.CountryID
Try this
results.Where(a=> arrayval.Contains(a.CountryId.ToString()).Aggregate("", (a,b)=> a+b);
I would create a list of your array values e.g.
List<string> list = new List<string>()
{
"2",
"12",
"20",
//etc...
};
and then do
var result = results.Where(p => list.Contains(p.countryId.ToString()));
Basically you are only select countryId's that are contained in the list.

linq - selecting elements not equal to something

Suppose I have a collection of strings.
How do I select all the elements that don't contain a certain parameter value?
List<string> TheList = .....
var TheCleanList = (from s in TheList
where s != parameter
select s).ToList();
I was thinking about where s!= parameter but I'm wondering if there's a cleaner way to do it.
Thanks.
If you don't need a new list you don't need Linq for this - use Remove()- this avoids having to create a new list:
If you want to remove all strings that are equal to Parameter:
TheList.RemoveAll(s => s == Parameter);
If you want to remove all strings that contain Parameter (not clear from your question):
TheList.RemoveAll(s => s.Contains(Parameter));
You mean:
List<string> TheList = .....
var TheCleanList = (from s in TheList
where !s.Contains(parameter)
select s).ToList();
You can use String.Contains
var TheCleanList = (from s in TheList
where !s.Contains(parameter)
select s).ToList();
Or
var TheCleanList = TheList.Where(s => !s.Contains(parameter)).ToList();
String.Contains is case-sensitive. If you want a case-insensitve:
string lower = parameter.ToLower();
...
where s.ToLower().Contains(lower)

Nested lists, how I can do this with lambda expression?

Can't really understand how the select extension method works with a list inside another list, like this:
var queries = (from item in list
from item2 in list.anotherlist
select item2).ToList<MyType>();
This will not work:
// Gives me a list of List<QueryResult>
var queries = list.Select(item => item.anotherlist).ToList();
The SelectMany operator ought to do the trick - in this case, it takes a list of lists and flattens it:
var queries = list.SelectMany(sublist => sublist).ToList();
use selectmany
var queries = list.SelectMany(l => l.anotherList).ToList();

List<T> Concatenation for 'X' amount of lists

I have for example 5 List all of the same type. Can I simply do
List<T> newset = List1.Concat(List2).Concat(List3).Concat(List4).....
You can do this (although you need .ToList() at the end).
However, it would be (slightly) more efficient to generate a single list, and use AddRange to add in each list. Just initialize the list with the total size of all of your lists, then call AddRange repeatedly.
You might want to consider doing something like:
public List<T> ConcatMultiple<T>(this List<T> list, params[] ICollection<T> others)
{
List<T> results = new List<T>(list.Count + others.Sum(i => i.Count));
results.AddRange(list);
foreach(var l in others)
results.AddRange(l);
return results;
}
Then calling via:
List<MyClass> newset = List1.ConcatMultiple(List2, List3, List4);
Yes, you can do that.
List<Thing> newSet = List1.Concat(List2).Concat(List3).Concat(List4).ToList();
If you want to concatenate an arbitrary (previously unknown) number of lists, then you may need to concatenate a collection of lists. Probably the easiest way to do this would be to use the SelectMany operator (or nested from clauses in LINQ query):
IEnumerable<List<int>> lists = /* get list of lists */;
List<int> result = lists.SelectMany(e => e).ToList();
The SelectMany operator calls the given function for every element of the input list (which is a list) and then concatenates all the resulting lists (the actual lists from your input list of lists). Alternatively using the LINQ query syntax:
List<int> result = (from l in lists
from e in l select e).ToList();
I believe that the C# compiler may actually optimize this, so that it doesn't iterate over all the individual elements (and does the same thing as the explicit version above). If you have a known number of lists, you can of course write:
List<int> result = (from l in new[] { list1, list2, list3, list4 }
from e in l select e).ToList();
It is not as elegant as defining your own method exactly for this purpose, but it shows how powerful the LINQ query syntax is.
you can, but do not forget to append .ToList(); in the end.
also you can call newset.AddRange(ListX); i think it is better in terms of performance
For variable list count:
IEnumerable<T> enumerable = Enumerable.Empty<T>();
foreach (List<T> list in [whatever])
enumerable = enumerable.Concat(list);
At the end you could add a "ToList()" if you want a rely List:
List<T> list = enumerable.ToList();
However, this might not be neeeded.
You certainly can do that, though it may not be incredibly efficient.
As stated by other answers, don't forget to add .ToList() to the end of your line of code, or use List1.AddRange(List2); List1.AddRange(List3); ... for added efficiency.
of you can use an union in LINQ if it is a real union that you want to do ofcourse...

Categories