C# compare lists List<T> - c#

using Microsoft.VisualStudio.TestTools.UnitTesting;
I want universal test method, which gets Dictionary and function, and then check equality for each dictionary entry between Value and function(Key):
public void TestMethod<TKey, TValue>(Dictionary<TKey, TValue> dict, Func<TKey, TValue> func)
{
foreach (var test in dict)
{
Assert.AreEqual(test.Value, func(test.Key));
}
}
But if Values (and return value of function) is
List<int>
it doesnt work, of course. So, I found than I need
CollectionAssert.AreEqual
for such cases.
But now I have to say, that my value is System.Collections.ICollection. How to do this?

You need to cast the values to ICollection so the compiler won't complain.
public void TestMethod<TKey, TValue>(Dictionary<TKey, TValue> dict, Func<TKey, TValue> func)
{
foreach (var test in dict)
{
if (test.Value is ICollection)
{
CollectionAssert.AreEqual((ICollection)test.Value, (ICollection)func(test.Key));
}
else
{
Assert.AreEqual(test.Value, func(test.Key));
}
}
}

Related

How to make a method generic in c#?

I have couple of methods and it keeps on expanding. So, I am planning to make it generic. Can anyone please help me with that. Atleast the method definition.
private static Dictionary<string, class1> PToDictionary(MapField<string, class1Proto> keyValuePairs)
{
Dictionary<string, class1> keyValues = new();
foreach (var pair in keyValuePairs)
{
**keyValues[pair.Key] = pToR(pair.Value);**
}
return keyValues;
}
My another method is :
private static Dictionary<Uri, class2> PToDictionary1(MapField<string, class2Proto> keyValuePairs)
{
Dictionary<string, class2> keyValues = new();
foreach (var pair in keyValuePairs)
{
**keyValues[new Uri(pair.Key)] = pToR1(pair.Value);**
}
return keyValues;
}
How can I make this generic so that when more methods are added, I dont need to add code.
I was thinking something like this, but errors are :
// Not sure how to call this method after Func is there
private static Dictionary<TKey, TValue> PToDictionary<TKey, TValue, TKeyProto, TValueProto>(MapField<TKeyProto, TValueProto> keyValuePairs, Func<TKeyProto, TKey> keyFunc, Func<TValueProto, TValue> valueFunc)
{
//How can I generalize my above method ?
}
Can someone help me complete the method ?
You don't need an extra method at all. LINQ already provides everything you need, combined with the fact that MapField implements IDictionary<TKey, TValue> (and therefore IEnumerable<KeyValuePair<TKey, TValue>>.
You'd just call:
var dictionary = repeatedField.ToDictionary(
pair => ConvertKey(pair.Key), pair => ConvertValue(pair.Value));
(where ConvertKey would be whatever code you want to convert the repeated field key into the dictionary key, and likewise for ConvertValue).
Sample calls:
var d1 = repeatedField1.ToDictionary(pair => pair.Key, pair => pToR(pair.Value));
var d2 = repeatedField2.ToDictionary(
pair => new Uri(pair.Key), pair => pToR1(pair.Value));
... but you may be able to remove the pToR and pToR1 methods anyway. (It's hard to tell without information about what they're doing...)
You can use the following method to convert MapField<TKeyProto, TValueProto> to Dictionary<TKey, TValue>:
public static Dictionary<TKey, TValue> PToDictionary<TKey, TValue, TKeyProto, TValueProto>(
MapField<TKeyProto, TValueProto> keyValuePairs,
Func<TKeyProto, TKey> mapKey,
Func<TValueProto, TValue> mapValue
)
{
Dictionary<TKey, TValue> keyValues = new();
foreach (var pair in keyValuePairs)
{
keyValues[mapKey(pair.Key)] = mapValue(pair.Value);
}
return keyValues;
}
Here, mapKey is a function that converts MapField's key to a dictionary key. Similarly, mapValue converts MapField's value to a dictionary value.
Another way is to make usage of LINQ ToDictionary extension method:
public static Dictionary<TKey, TValue> PToDictionary<TKey, TValue, TKeyProto, TValueProto>(
MapField<TKeyProto, TValueProto> keyValuePairs,
Func<TKeyProto, TKey> mapKey,
Func<TValueProto, TValue> mapValue
)
{
// this is possible because MapField<TKey, TValue> implements IEnumerable<KeyValuePair<TKey, TValue>>
return keyValuePairs.ToDictionary(
(KeyValuePair<TKeyProto, TValueProto> kvp) => mapKey(kvp.Key),
(KeyValuePair<TKeyProto, TValueProto> kvp) => mapValue(kvp.Value));
}
For example, if you want to convert MapField<string, string> to Dictionary<Uri, int> you can use the following code:
Dictionary<Uri, int> dictionary = PToDictionary(
map,
key => new Uri(key),
val => int.Parse(val));

How to read the value from a Dictionary via .TryGetValue() if the value is a tuple?

I have a dictionary of type
Dictionary<int, (float, float)>
when trying to read the value from it I can't use this way
if (myDict.TryGetValue(1, out (float tupleItem1, float tupleItem2))) { /* ... */ }
because then I get compile errors
The way it works is
if (myDict.TryGetValue(1, out (float, float) theTuple)) { /* ... */ }
Is there a way I can directly initialize the variables like so?
if (!myDict.TryGetValue(1, out (float tupleItem1, float tupleItem2)))
{
/* handle if not found */
tupleItem1 = 111;
tupleItem2 = -12345;
}
You can't deconstruct directly in an out parameter yet unfortunately, see this proposal.
You'll have to deconstruct it yourself:
if (!myDict.TryGetValue(1, out var result))
{
result = (111, -12345);
}
You can improve this situation slightly with an extension method:
public static class DictionaryExtensions
{
public static TValue? TryGetValue<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key) where TValue : struct
{
return dict.TryGetValue(key, out var result) ? result : null;
}
}
This lets you write:
if (myDict.TryGetValue(1) is not (float tupleItem1, float tupleItem2))
{
tupleItem1 = 111;
tupleItem2 = -12345;
}
If you find yourself doing this a lot, you could write a simple little extension method to make it more readable:
public static class DictionaryExt
{
public static TValue TryGetValueOrDefault<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key, Func<TValue> getDefault)
{
return dict.TryGetValue(key, out var value)
? value
: getDefault();
}
}
Then your sample code could looks something like this:
var dict = new Dictionary<int, (float, float)>();
var result = dict.TryGetValueOrDefault(1, () => (111, -12345));
Console.WriteLine(result);
I chose to use Func<TValue> rather than TValue for the default so that you don't have to create a default value that isn't going to be used in the case that the dictionary already contains the key.
If you want a slightly simpler syntax and you don't care that the default is created for every call regardless of whether it's actually needed you could write it like this instead:
public static class DictionaryExt
{
public static TValue TryGetValueOrDefault<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key, TValue defaultValue)
{
return dict.TryGetValue(key, out var value)
? value
: defaultValue;
}
}
Which would be called like this:
var dict = new Dictionary<int, (float, float)>();
var result = dict.TryGetValueOrDefault(1, (111, -12345));
Console.WriteLine(result);
You could of course include both methods in DictionaryExt for more flexibility.
(It's also entirely possible that the overhead of creating a Func<TValue> for every call is greater than creating a tuple for each call, so if you're worried about performance you should test it. In either case, you could pass in a precreated Func or Tuple to avoid the creation overhead.)

Create Extension Method TryGetValue(TKey, out TValue) of Enumerable<KeyValuePair<TKey, TValue>> just like of Dictionary<TKey, TValue>

I have a Enumerable<KeyValuePair<TKey, TValue>>. I want to create a bool TryGetValue(TKey, out TValue) extension method of it just like it is available in Dictionary<TKey, TValue>.
I tried
public static bool TryGetValue<TKey, TValue>
(this Enumerable<KeyValuePair<TKey, TValue>> mapping, TKey key, out TValue value)
{
bool retVal = false;
KeyValuePair<TKey, TValue> kvp;
kvp = mapping.First(x => x.Key.Equals(key));
if(kvp.Key == null && kvp.Value == null)
{
retVal = false;
value = default(TValue);
}
else
{
retVal = true;
value = kvp.Value;
}
return retval;
}
Is this correct way? If not please suggest one.
Note:
I cannot use a Dictionary because Keys are repeated. Moreover it will only return the first matching value?
What happens to the rest?
We can leave them. I am sending KeyValuePair created from a DataTable. I am creating that DataTable using order by columnname in its query.
Why not just use a simple foreach loop?
Example:
public static bool TryGetValue<TKey, TValue>
(this KeyValuePair<TKey, TValue>[] mapping, TKey key, out TValue value)
{
foreach(var kvp in mapping)
if (kvp.Key.Equals(key))
{
value = kvp.Value;
return true;
}
value = default(TValue);
return false;
}
Your implementation will throw an exception if the key doesn't exists due to .First(), and FirstOrDefault() would be ugly since KeyValuePair is a struct and hence you can't just compare it to null.
Sidenote:
Instead of extending KeyValuePair<TKey, TValue>[], you probably want to use IEnumerable<KeyValuePair<TKey, TValue>> instead to be more flexible.

Lookup extension method

Rather than create a whole new class implementing ILookup<T> is it possible to add an extension method to dictionary which caters for it? I'm thinking something along the following:
public static void LookupAdd(this Dictionary<T, List<V>> dict, T key, V item)
{
if (!dict.ContainsKey(key))
{
dict.Add(key, new List<T>());
}
dict[key].Add(item);
}
This fails to compile saying it can't identify the types. I'm guessing that my generic parameters are too complex (particularly List<V>)
You have forgotten to add the generic parameter syntax:
public static void LookupAdd<T, V>(this Dictionary<T, List<V>> dictionary, T key, V item)
{
}
The <T, V> is missing.
Try...
public static void LookupAdd<T,V>(this Dictionary<T, List<V>> dict, T key, V item)
{
if (!dict.ContainsKey(key))
{
dict.Add(key, new List<V>());
}
dict[key].Add(item);
}
UPDATE:
Notice that you should have
new List<V>()
where you have
new List<T>()

Best way to remove multiple items matching a predicate from a .NET Dictionary?

I need to remove multiple items from a Dictionary.
A simple way to do that is as follows :
List<string> keystoremove= new List<string>();
foreach (KeyValuePair<string,object> k in MyCollection)
if (k.Value.Member==foo)
keystoremove.Add(k.Key);
foreach (string s in keystoremove)
MyCollection.Remove(s);
The reason why I can't directly Remove the items in the foreach block is that this would throw an Exception ("Collection was modified...")
I'd like to do the following :
MyCollection.RemoveAll(x =>x.Member==foo)
But the Dictionary<> class doesn't expose a RemoveAll(Predicate<> Match) method, like the List<> Class does.
What's the best way (both performance wise and elegant wise) to do that?
Here's an alternate way
foreach ( var s in MyCollection.Where(kv => kv.Value.Member == foo).ToList() ) {
MyCollection.Remove(s.Key);
}
Pushing the code into a list directly allows you to avoid the "removing while enumerating" problem. The .ToList() will force the enumeration before the foreach really starts.
you can create an extension method:
public static class DictionaryExtensions
{
public static void RemoveAll<TKey, TValue>(this IDictionary<TKey, TValue> dict,
Func<TValue, bool> predicate)
{
var keys = dict.Keys.Where(k => predicate(dict[k])).ToList();
foreach (var key in keys)
{
dict.Remove(key);
}
}
}
...
dictionary.RemoveAll(x => x.Member == foo);
Instead of removing, just do the inverse. Create a new dictionary from the old one containing only the elements you are interested in.
public Dictionary<T, U> NewDictionaryFiltered<T, U>
(
Dictionary<T, U> source,
Func<T, U, bool> filter
)
{
return source
.Where(x => filter(x.Key, x.Value))
.ToDictionary(x => x.Key, x => x.Value);
}
Modified version of Aku's extension method solution. Main difference is that it allows the predicate to use the dictionary key. A minor difference is that it extends IDictionary rather than Dictionary.
public static class DictionaryExtensions
{
public static void RemoveAll<TKey, TValue>(this IDictionary<TKey, TValue> dic,
Func<TKey, TValue, bool> predicate)
{
var keys = dic.Keys.Where(k => predicate(k, dic[k])).ToList();
foreach (var key in keys)
{
dic.Remove(key);
}
}
}
. . .
dictionary.RemoveAll((k,v) => v.Member == foo);
Starting from the .NET 3.0, it's now allowed to remove items from a Dictionary<TKey,TValue> while enumerating it. According to the documentation:
.NET Core 3.0+ only: The only mutating methods which do not invalidate enumerators are Remove and Clear.
Here is the GitHub issue where this change was proposed and approved: Allow Dictionary<K,V>.Remove during enumeration
So the RemoveAll extension method can be implemented simply like this:
/// <remarks>.NET Core 3.0+ only.</remarks>
public static void RemoveAll<TKey, TValue>(this Dictionary<TKey, TValue> source,
Predicate<KeyValuePair<TKey, TValue>> predicate)
{
foreach (var pair in source)
if (predicate(pair))
source.Remove(pair.Key);
}
Usage example:
myDictionary.RemoveAll(e => e.Value.Member == foo);
The fastest way to remove would be either:
public static void RemoveAll<TKey, TValue>(this IDictionary<TKey, TValue> idict, Func<KeyValuePair<TKey, TValue>, bool> predicate)
{
foreach (var kvp in idict.Where(predicate).ToList())
{
idict.Remove(kvp.Key);
}
}
or
public static void RemoveAll<T>(this ICollection<T> icollection, Predicate<T> predicate)
{
var nonMatchingItems = new List<T>();
// Move all the items that do not match to another collection.
foreach (var item in icollection)
{
if (!predicate(item))
{
nonMatchingItems.Add(item);
}
}
// Clear the collection and then copy back the non-matched items.
icollection.Clear();
foreach (var item in nonMatchingItems)
{
icollection.Add(item);
}
}
depending on whether you have more cases of predicate returning true or not. Both are O(N) in nature, but 1st approach will be faster if you have very less cases of "removal/lookup", and the second one faster if items in collection matches the condition majority of the times.
Can you just change your loop to use an index (i.e. FOR instead of FOREACH)? You'd have to loop backwards, of course, i.e. count-1 down to zero.
Instead of removing just do the inverse (create a new dictionary from the old one containing only the elements you are interested in) and let the garbage collector take care of the old dictionary:
var newDictionary = oldDictionary.Where(x => x.Value != foo);
It's simple using LINQ. Just do the following :)
MyCollection = MyCollection.Where(mc => !keystoremove.Contains(mc.Key))
.ToDictionary(d => d.Key, d => d.Value);

Categories

Resources