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...
Related
I have a list of tuples, the objects in the tuple are both the same type. The data structure of a list of tuples is needed until we get to error handling. To optimize error handling, I would like to flatten the tuples into a single list to allow for duplicate checking:
For instance if I had List<Tuple<string,string>>() (my types are more complex but the idea should hold):
[<"Tom","Dick">, <"Dick","Harry">, <"Bob","John">]
I would like to end up with:
["Tom", "Dick", "Harry", "Bob", "John"]
I know I could do this with:
List<string> stringList = List<string>();
Foreach(var item in tupleList){
stringList.Add(item.Item1);
stringList.Add(item.Item2);
}
stringList = stringList.Distinct();
But I am hoping for a more efficient way, perhaps something built into Linq. There is no guarantee of duplicates, but due to the performance cost of error handling, I would rather handle each only once.
If you need distinct items without order - use HashSet:
HashSet<string> stringList = new HashSet<string>();
foreach(var item in tupleList){
stringList.Add(item.Item1);
stringList.Add(item.Item2);
}
You can do similar code with LINQ, but it will not be faster (and probably not better looking as you need to convert Tuple to enumerable for most operations). You can try Aggregate if you really looking for LINQ.
Its simple by using linq SelectMany method
var tupleList = Enumerable.Range(0, 10).Select(i => new Tuple<string, string>(i.ToString(), "just for example")); // tuples
var trg = tupleList.SelectMany(t => new[] { t.Item1, t.Item2 }).Distinct();
One line, however still not a tetris in one line Ж)
As a slight variation on the above you could also do this:
HashSet<string> hash= new HashSet<string>();
tupleList.ForEach(l => hash.UnionWith(new string[] { l.Item1, l.Item2 }));
Although I like the SelectMany example in the comments of the question
I have list of objects of a class for example:
class MyClass
{
string id,
string name,
string lastname
}
so for example: List<MyClass> myClassList;
and also I have list of string of some ids, so for example:
List<string> myIdList;
Now I am looking for a way to have a method that accept these two as paramets and returns me a List<MyClass> of the objects that their id is the same as what we have in myIdList.
NOTE: Always the bigger list is myClassList and always myIdList is a smaller subset of that.
How can we find this intersection?
So you're looking to find all the elements in myClassList where myIdList contains the ID? That suggests:
var query = myClassList.Where(c => myIdList.Contains(c.id));
Note that if you could use a HashSet<string> instead of a List<string>, each Contains test will potentially be more efficient - certainly if your list of IDs grows large. (If the list of IDs is tiny, there may well be very little difference at all.)
It's important to consider the difference between a join and the above approach in the face of duplicate elements in either myClassList or myIdList. A join will yield every matching pair - the above will yield either 0 or 1 element per item in myClassList.
Which of those you want is up to you.
EDIT: If you're talking to a database, it would be best if you didn't use a List<T> for the entities in the first place - unless you need them for something else, it would be much more sensible to do the query in the database than fetching all the data and then performing the query locally.
That isn't strictly an intersection (unless the ids are unique), but you can simply use Contains, i.e.
var sublist = myClassList.Where(x => myIdList.Contains(x.id));
You will, however, get significantly better performance if you create a HashSet<T> first:
var hash = new HashSet<string>(myIdList);
var sublist = myClassList.Where(x => hash.Contains(x.id));
You can use a join between the two lists:
return myClassList.Join(
myIdList,
item => item.Id,
id => id,
(item, id) => item)
.ToList();
It is kind of intersection between two list so read it like i want something from one list that is present in second list. Here ToList() part executing the query simultaneouly.
var lst = myClassList.Where(x => myIdList.Contains(x.id)).ToList();
you have to use below mentioned code
var samedata=myClassList.where(p=>p.myIdList.Any(q=>q==p.id))
myClassList.Where(x => myIdList.Contains(x.id));
Try
List<MyClass> GetMatchingObjects(List<MyClass> classList, List<string> idList)
{
return classList.Where(myClass => idList.Any(x => myClass.id == x)).ToList();
}
var q = myClassList.Where(x => myIdList.Contains(x.id));
If I have two list and I want to create a new third list that has only the common elements in the two list (a where in query) can use this code:
var listC = listB.Join(listA, b => b.ObjectAId, a => a.Id, (b, a) => b).ToList();
This way has an O(n) complexity.
However, I also can use a select method in this way:
var lstC = listA.Where(r => listB.Contains(r).ToList();
This second way is O(n) too?
If the two ways has the same efficient, which differences are between both of them?
Thanks.
var listC = listA.Intersect(listB); // perhaps a .ToList() on the end
This will use hashing to keep it as cheap as possible.
how about
var commonElements = listA.Intersect(listB).ToList();
You could try using the Enumerable.Intersect function, which takes two lists and turns them into one which has all the elements that are in both lists. There is also an overload that takes an IEqualityComparer<T> if you want the equality of the objects not to be based on reference equality/default IEqualityComparer<T> for your class.
Here's how you'd use it:
var commonElements = listA.Intersect(listB);
//you can add an IEqualityComparer<T> to the arguments,
//or append .ToList()/.ToArray to make it a list/array.
I am doing the following...
//first I have a list of sports...
List<string> sports = new List<string> {"football","basketball"}
//then I have a list of partners who are offering that sport
List<Partner> = Partner.GetAvailablePartners();
//Partner is a type that has a List<string> Sports members.
Now what I want to do is filter my list of Partners so that only partners who are offering the sports contained in sports but I can't figure out how.
I thought could use the Intersection extension method like this...
var filteredPartners = (List<Partner>) (from p in partners where p.Sports.Intersect(sports).Count()>0 select p);
but I it doesn't work I guess because I am acting on a member list not the root list.
Can this be done with the intersect (or some other linq) method?
Seth
If you really need the results in a List then call ToList() at the end of your LINQ statement. Otherwise, you should be able to do:
IEnumerable<Partner> partners = partners.Where(p => p.Sports.Intersect(sports).Count() == sports.Count);
...or in a resultant List:
List<Partner> partners = partners.Where(p => p.Sports.Intersect(sports).Count() == sports.Count).ToList();
.Where() and all other lINQ methods return an IEnumerable<T> with lazy iteration, not List<T>.
You can't cast them to List<T>.
If you want a List<T>, call ToList().
Use intersect.
Example using two IEnumerables
var ids = original.Select(x => x.ID).Intersect(yourEnumerable);
What am I missing here?
I want to do a simple call to Select() like this:
List<int> list = new List<int>();
//fill the list
List<int> selections = (List<int>)list.Select(i => i*i); //for example
And I keep having trouble casting it. What am I missing?
Select() will return you an IEnumerable<int> type, you have to use the ToList() operator:
List<int> selections = list.Select(i => i*i).ToList();
Select() doesn't return a List so of course you can't cast it to a list.
You can use the ToList method instead:
list.Select(i => i*i).ToList();
As others have said, Select returns an IEnumerable<T> which isn't actually a list - it's the result of a lazily-evaluated iterator block.
However, if you're dealing with lists and you want a list back out with nothing other than a projection, using List<T>.ConvertAll will be more efficient as it's able to create the new list with the right size immediately:
List<int> selections = list.ConvertAll(i => i*i);
Unless you particularly care about the efficiency, however, I'd probably stick to Select as it'll give you more consistency with other LINQ code.