C#: Union of two ICollections? (equivalent of Java's addAll()) - c#

I have two ICollections of which I would like to take the union. Currently, I'm doing this with a foreach loop, but that feels verbose and hideous. What is the C# equivalent of Java's addAll()?
Example of this problem:
ICollection<IDictionary<string, string>> result = new HashSet<IDictionary<string, string>>();
// ...
ICollection<IDictionary<string, string>> fromSubTree = GetAllTypeWithin(elementName, element);
foreach( IDictionary<string, string> dict in fromSubTree ) { // hacky
result.Add(dict);
}
// result is now the union of the two sets

You can use the Enumerable.Union extension method:
result = result.Union(fromSubTree).ToList();
Since result is declared ICollection<T>, you'll need the ToList() call to convert the resulting IEnumerable<T> into a List<T> (which implements ICollection<T>). If enumeration is acceptable, you could leave the ToList() call off, and get deferred execution (if desired).

AddRange() appends the source list to the end of another, and may suit your needs.
destList.AddRange(srcList);

LINQ's Enumerable.Union will work:

Related

Convert list of of objects to list of tuple without iterating

I'm trying to add an extra parameter to a list of ef objects to track processing, but I keep running into having to initialize each list item explicitly. What's the correct linq way to do this? Aside from terseness, is there any advantage to a linq syntax in this case?
List<app_subjects> subjectList = AppMySQLQueries.GetAllSubjects();
List<Tuple<app_subjects, bool>> subjectCollection = new List<Tuple<app_subjects, bool>>(subjectList.Count);
foreach (app_subjects subject in subjectList)
{
subjectCollection.Add(Tuple.Create(subject, false));
}
I have searched the site without success.
You just want to use a projection here ( Select ) which applies the transformation in your lambda expression to each element in the source collection.
List<Tuple<app_subjects, bool>> tuples = subjectList.Select(x => new Tuple<app_subjects, bool>(x, false)).ToList();
The ToList() call is not entirely necessary, if you removed it then the method will return an IEnumerable<Tuple<app_subjects, bool>>. If you're just going to iterate the collection of tuples afterwards the ToList call should be removed as it forces execution (enumerates the IEnumberable) and then your next operation (the foreach) would do the same, making the code perform worse.
Like this?
subjectList.Select(s => Tuple.Create(s, false)).ToList();
With C# 10.0 (.NET 6.0) this is even easier and cleaner. Along with named tuples we can also declare a tuple by simply putting the values in round brackets.
List<(string NamedProperty1, int NamedProperty2)> _tuples = new();
_tuples = _objectList.Select(o => (o.SomeProperty1, o.SomeProperty2)).ToList();
try this.
List<Tuple<app_subjects, bool>> subjectCollection = subjectList.CovertAll( subject => new Tuple<app_subjects, bool>(){
subject,
false
}).ToList();

Intersecting number of keyValuePair Lists according to the Key element

I have number of lists of type:
public List<KeyValuePair<KeyValuePair<string, string>,
List<KeyValuePair<string, string>>>> rawComparisonObject;
I want to get the intersection of these lists according to the "key" of the KeyValuePair that constructs the List
I tried:
List2 = list1.Intersect(list2).Intersect(list3)...... etc , but as you can see it Intersects all the KeyValuePair variable, not the one I want.
I also tried
Intersect lists on KeyValuePair key?
In the following form:
public List<List<KeyValuePair<KeyValuePair<string, string>, List<KeyValuePair<string, string>>>>> getCommon(List<ResourceInformation> input)
{
List<List<KeyValuePair<KeyValuePair<string, string>, List<KeyValuePair<string, string>>>>> rawComparisonObject =
new List<List<KeyValuePair<KeyValuePair<string,string>,List<KeyValuePair<string,string>>>>>();
foreach (ResourceInformation item in input)
{
rawComparisonObject.Add(item.rawComparisonObject);
}
foreach (List<KeyValuePair<KeyValuePair<string, string>, List<KeyValuePair<string, string>>>> item in rawComparisonObject)
{
}
List<List<KeyValuePair<KeyValuePair<string, string>, List<KeyValuePair<string, string>>>>> common =
new List<List<KeyValuePair<KeyValuePair<string, string>, List<KeyValuePair<string, string>>>>>();
for (int i = 0; i < (rawComparisonObject.Count-1); i++)
{
var keysFromB = new HashSet<KeyValuePair<string, string>>(rawComparisonObject[i].Select(x => x.Key));
var result = rawComparisonObject[i+1].Where(x => keysFromB.Remove(x.Key));
common.Add(result.ToList());
}
return common;
}
it returned very faulty values,
is there
Any easy way to do this ?
I use this data structure in linked data work, to get common objects as a result of comparing between objects
Ex: Batman vs. Inception
should return:
Type : Movie | Movie
Starring : Christian Bale | Leonardo Dicaprio
of course everything is highlighted with it's URI link, that's why I need keyValuePair one for URI and other for label....
I tried my best to explain this complex data-structure. hope it's clear enough
As I understand the code you've written, here's my (revised) translation:
public List<List<KeyValuePair<KeyValuePair<string, string>, List<KeyValuePair<string, string>>>>> getCommon(List<ResourceInformation> input)
{
var rawComparisonObject =
input.Select(item => item.rawComparisonObject).ToList();
var common = rawComparisonObject.Zip(
rawComparisonObject.Skip(1),
(prevItems, nextItems) =>
(from next in nextItems
join prev in prevItems on next.Key equals prev.Key
select next).ToList()).ToList();
return common;
}
Edit: the above translation, omits the empty foreach loop in the middle and uses the join as a filter, projecting only the 'next' elements that pass the join criteria. I tend to favor join for this kind of filtering as I know it utilizes hashing under the covers to efficiently perform the matching it does.
The problem with my prior version was that it collected the join results using a 'group join' variable which led to that extra enumerable that we didn't want. After the change, the inner ToList() is analogous to the result variable in the original code sample provided in the post. The outer ToList() is the final common variable's (re)packaging of the results. I believe this will provide results similar to that of the original code; however, I strongly encourage testing to verify that the results meet expectations.
IMHO, the right thing to do would be to refactor to simplify the generics use until we can reason about them better. In a brief interim attempt I changed GetCommon to a generic type like this (later changing it back):
public List<List<KeyValuePair<T, List<T>>>> GetCommon<T>(/*List<ResourceInformation> input*/)
From there, we could promote the rawComparisonObject list to a parameter of the method - and in the process of doing so, we would replace the current parameter of the method. The use of var typing allows us to avoid changing the type for the common local variable (so long as we're careful that the output type matches the expected return type, which was my bad on the original translation.)
There are many more design ideas and questions than I could comfortably examine here, so I am going to close without attempting to do so. I do want to offer that this was a good challenge - sometimes LINQ isn't the right choice, but even when it isn't the right choice, a change of approach can make it worth trying. Thanks!
you can do this with linq, although likely you should change your data model to be more efficient:
var keys = list1.select( kv => kv.Key).intersection(list2.select(kv => kv.Key)
var result = list1.where( key => keys.contains(key).TolLst()
If you only want to intersect the KeyValuePairs on their key you should implement a custom IEqualityComparer<T> and use Intersect() method like this:
class KeyValyePairComparer : IEqualityComparer<KeyValuePair<string, string>>
{
public bool Equals(KeyValuePair<string, string> x, KeyValuePair<string, string> y)
{
return x.Key == y.Key;
}
public int GetHashCode(KeyValuePair<string, string> item)
{
return item.Key.GetHashCode();
}
}
Using the implementation above you can get the intersection with the query:
var comparer = new KeyValuePairComparer();
var intersection = list1.Intersect(list2, comparer).Intersect(list3, comparer);

How to get an empty list of a collection?

I have a collection of anonymous class and I want to return an empty list of it.
What is the best readable expression to use?
I though of the following but I don't think they are readably enough:
var result = MyCollection.Take(0).ToList();
var result = MyCollection.Where(p => false).ToList();
Note: I don't want to empty the collection itself.
Any suggestion!
Whats about:
Enumerable.Empty<T>();
This returns an empty enumerable which is of type T. If you really want a List so you are free to do this:
Enumerable.Empty<T>().ToList<T>();
Actually, if you use a generic extension you don't even have to use any Linq to achieve this, you already have the anonymous type exposed through T
public static IList<T> GetEmptyList<T>(this IEnumerable<T> source)
{
return new List<T>();
}
var emp = MyCollection.GetEmptyList();
Given that your first suggestion works and should perform well - if readability is the only issue, why not create an extension method:
public static IList<T> CreateEmptyCopy(this IEnumerable<T> source)
{
return source.Take(0).ToList();
}
Now you can refactor your example to
var result = MyCollection.CreateEmptyCopy();
For performance reasons, you should stick with the first option you came up with.
The other one would iterate over the entire collection before returning an empty list.
Because the anonymous type there is no way, in source code, to create a list. There is, however, a way to create such list through reflection.

C# - Populate a list using lambda expressions or LINQ

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));

C# convert reflection.propertyinfo to Generic.List<>

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();

Categories

Resources