I'm finding myself in need of "combining" several instances of the same type. This type has several IList properties on it. I want to take each instance and combine the values of those IList properties across the instances, so my code only needs one of those instances.
I'm thinking of creating an ICombinable interface, but I'm wonder if there's something already out there that's suited to this?
public interface ICombinable<T>
{
void CombineWith(T instance);
}
Have you tried looking at System.Collections.Generic.HashSet<T>? If you add the same thing multiple times, only 1 item exists.
Sounds like you need Concat
var configs = dbConfig.configList.Concat(fileConfig.configList);
I ended up using SelectMany and Select for this. IConfiguration is an interface for the MyConfigurationInfo class. GetMyConfigurationSources returns all the different IConfigurations (from files, DB, etc).
// accumulates an enumerable property on IConfiguration
public static IEnumerable<TValue> GetConfigurationValues<TValue>(Func<IConfiguration, IEnumerable<TValue>> selector)
{
// cast included for clarification only
return (GetMyConfigurationSources() as IEnumerable<IConfiguration>)
.Where(c => selector(c) != null)
.SelectMany(selector);
}
// accumulates a non enumerable property on IConfiguration
public static IEnumerable<TValue> GetConfigurationValues<TValue>(Func<IConfiguration, TValue> selector)
{
// cast included for clarification only
return (GetMyConfigurationSources() as IEnumerable<IConfiguration>)
.Where(c => selector(c) != null)
.Select(selector);
}
// Example usage:
static void Main()
{
string[] allEnumerableValues = GetConfigurationValues(c => c.SomeEnumerableConfigPropertyOfStrings);
string[] allNonEnumerableValues = GetConfigurationValues(c => c.SomeNonEnumerableConfigPropertyString);
}
Related
Let's say I have the following object:
public class MyObject
{
public string MyValue { get; set; }
}
And in another class I have a list of these objects:
public class MyClass
{
private List<MyObject> _list;
public MyClass(List<MyObject> myObjects)
{
_list = myObjects;
}
public bool AllUniqueValues()
{
...
}
}
I want to check if all MyObjects in the list have an unique (non-duplicated) Value. When I use the following it works:
public bool AllUnique()
{
return _list.All(x => _list.Count(y => String.Equals(y.Value, x.Value)) == 1);
}
But I have the feeling this can be done easier / more elegant. So, my question, is there a better / more elegant approach to check if all MyObjects have a non-duplicated Value, and if so, how?
I find this quite elegant:
public static class EnumerableExtensions
{
public static bool AllUnique<TSource, TResult>(this IEnumerable<TSource> enumerable,
Func<TSource, TResult> selector)
{
var uniques = new HashSet<TResult>();
return enumerable.All(item => uniques.Add(selector(item)));
}
}
And now your code becomes:
var allUnique = _list.AllUnique(i => i.MyValue);
One of many way to do it:
return !_list.GroupBy(c=>c.MyValue).Any(c=>c.Count() > 1);
At least it is a little bit more clear.
The most elegant way of solving this is using a set data structure. An unordered collection of unique elements. In .NET, you need to use HashSet<T>.
You can either override Equals and GetHashCode of MyObject to provide what equality means in your case, or implement an IEqualityComparer<T>.
If you instantiate HashSet<T> and you don't provide an IEqualityComparer<T> implementation, then it will use your overrides, otherwise it will use the whole implementation. Usually you implement equality comparers if there're more than a meaning of equality for the same object.
I might still need an ordered collection of elements
If you still need to store your objects in order, you can both store the elements in both the HashSet<T> and List<T> in parallel. What you get with HashSet<T> is a practically O(1) access to your items when you need check if an item exists, get one or perform some supported operations in the collection, since it's a hashed collection, it won't need to iterate it entirely to find the element.
There are many ways to do it, but personally, I'd do the following:
public bool AllUnique()
{
return _list.GroupBy(x => x.MyValue).Count() == _list.Count();
}
How can I get the key values of a generic IDictionary<,> using reflection.
This is the type of thing I want to do.
public static string Format<T>(T item)
{
if (item.GetType().GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IDictionary<,>)))
{
// I know it's a IDictionary so figure out what the types are
Type keyType = item.GetType().GetGenericArguments()[0];
Type valueType = item.GetType().GetGenericArguments()[1];
//Now cast it to the correct IDictionary. How do I properly inject the type here?
var keyList = ((IDictionary<keyType, valueType>)item).Select(x => x.Key.ToString()).ToArray<string>();
}
}
Edit: Clarified that I want to use reflection
I think you are overcomplicating things. When I look at your code, you are trying to do the following:
myDictionary.Keys.Select(k => k.ToString()).ToArray();
So,
public string Format<T>(T value) {
if (##item is dictionary) {
var items = name.GetType().GetProperty("Keys", BindingFlags.Instance | BindingFlags.Public).GetValue(item) as IEnumerable;
if (items == null) throw new ArgumentException("Dictionary with no keys?");
string[] data = items.OfType<object>().Select(o => o.ToString()).ToArray();
}
}
Unfortunately you cannot pass a System.Type as a type argument. If you want to use the IDictionary<,> properties, you need to do a little more reflection.
var dictionaryType = typeof(IDictionary<,>).MakeGenericType(keyType, valueType);
var keysProperty = dictionaryType.GetProperty("Keys");
var keys = ((IEnumerable)keysProperty.GetValue(item)).OfType<object>().Select(k => k.ToString()).ToArray<string>();
However, if all you want are the keys, you can just use the non-generic IDictionary interface, and don't bother with reflection.
var dictionary = item as IDictionary;
if (dictionary != null)
{
var keyList = dictionary.Select(x => x.Key.ToString()).ToArray<string>();
}
You got a few problems here. One minor issue is you don't use the found interface for getting the generic arguments.
The other bigger problem is you're trying to use dynamically found types in types defined statically at compile time (IDictionary<keyType, valueType>).
If you want to continue down this road it's using reflection, which can be hard. Depending on your goal you could choose another path and try this out:
public static string Format<TKey,TValue>(IDictionary<TKey,TValue> item)
{
var keyList = item.Select(x => x.Key.ToString()).ToArray();
// do some work with keyList and return a string.
}
This will still work public static string Format<T>(T item) handling other types, so implementing this beside it:
public static string Format<T>(T item)
{
// handle non IDictionary<,> objects here
}
Making you able to call format anywhere:
Format(new Dictionary<string,int> { { "hello world", 1337 } });
Format("string");
Format(new { Hello = "World" });
The issue is that you're trying to get generic code parameters from Type objects. This is not directly possible, because Type is a class like nay other, it just represents a class, and type arguments are used to compile the method. Thus, you can't get new type arguments within the underlying code...
That being said, You could add extra generic parameters, with specific constraints,
public static Format<T, TKey, TValue>(T item)
where T : IDictionary<TKey, TValue>
Or, to be more succinct
public static Format<TKey, TValue>(IDicitonary<TKey, TValue> item)
This can then be called using dynamic so as to ensure the proper arguments are used
public static string Format<T>(T item)
{
if (item.GetType().GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IDictionary<,>)))
{ FormatDictionary((dynamic) item); }
}
private static FormatDictionary<TKey, TValue>(IDicitonary<TKey, TValue> item)
If you must perform these calls with Type objects, you'll have do so via metacode - either with more reflection calls, or by compiling a method using Expressions
I have the following Method
public static List<T> MergeAndSort<T>(List<List<T>> listOfLists) where T : Foo
{
List<T> list = listOfLists.SelectMany(bunch => bunch).ToList();
list.OrderBy(x => x.FooLongMember);
return list;
}
I look for a solution that provides a completely generic version. Currently I need to specify what T is as well as specify the specific member name within Foo in order to order by such member. The member currently is of type long. Can I rewrite the function to at least not have to specify that I pass in a List of Lists of type Foo? I target C#, .Net4.0. Thanks
something like this?
public static IOrderedEnumerable<T> MergeSortWrapper<T,TKey>(
IEnumerable<IEnumerable<T>> listOfLists,
Func<T,TKey> keySelector)
{
return listOfLists.SelectMany(bunch => bunch)
.OrderBy(keySelector);
}
-
var result = MergeSortWrapper(listOfListOfFoos, x => x.FooLongMember).ToList();
I'm trying to maintain a list of unique models from a variety of queries. Unfortunately, the equals method of our models are not defined, so I couldn't use a hash map easily.
As a quick fix I used the following code:
public void AddUnique(
List<Model> source,
List<Model> result)
{
if (result != null)
{
if (result.Count > 0
&& source != null
&& source.Count > 0)
{
source.RemoveAll(
s => result.Contains(
r => r.ID == s.ID));
}
result.AddRange(source);
}
}
Unfortunately, this does not work. When I step throught the code, I find that even though I've checked to make sure that there was at least one Model with the same ID in both source and result, the RemoveAll(Predicate<Model>) line does not change the number of items in source. What am I missing?
The above code shouldn't even compile, as Contains expects a Model, not a predicate.
You can use Any() instead:
source.RemoveAll(s => result.Any(r => r.ID == s.ID));
This will remove the items from source correctly.
I might opt to tackle the problem a different way.
You said you do not have suitable implementations of equality inside the class. Maybe you can't change that. However, you can define an IEqualityComparer<Model> implementation that allows you to specify appropriate Equals and GetHashCode implementations external to the actual Model class itself.
var comparer = new ModelComparer();
var addableModels = newSourceOfModels.Except(modelsThatAlreadyExist, comparer);
// you can then add the result to the existing
Where you might define the comparer as
class ModelComparer : IEqualityComparer<Model>
{
public bool Equals(Model x, Model y)
{
// validations omitted
return x.ID == y.ID;
}
public int GetHashCode(Model m)
{
return m.ID.GetHashCode();
}
}
source.RemoveAll(source.Where(result.Select(r => r.ID).Contains(source.Select(s => s.ID))));
The goal of this statement is to make two enumerations of IDs, one for source and one for result. It then will return true to the where statement for each of the elements in both enumerations. Then it will remove any elements that return true.
Your code is removing all the models which are the same between the two lists, not those which have the same ID. Unless they're actually the same instances of the model, it won't work like you're expecting.
Sometimes I use these extension methods for that sort of thing:
public static class CollectionHelper
{
public static void RemoveWhere<T>(this IList<T> list, Func<T, bool> selector)
{
var itemsToRemove = list.Where(selector).ToList();
foreach (var item in itemsToRemove)
{
list.Remove(item);
}
}
public static void RemoveWhere<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, Func<KeyValuePair<TKey, TValue>, bool> selector)
{
var itemsToRemove = dictionary.Where(selector).ToList();
foreach (var item in itemsToRemove)
{
dictionary.Remove(item);
}
}
}
I need help making this method generic. It is repeated about ten times to get lists for different web list controls (substituting "MyType" for the type used in the particular control).
private static IList<MyType> GetList(RequestForm form)
{
// get base list
IMyTypeRepository myTypeRepository = new MyTypeRepository(new HybridSessionBuilder());
IList<MyType> myTypes = myTypeRepository.GetAll();
// create results list
IList<MyType> result = new List<MyType>();
// iterate for active + used list items
foreach (MyType myType in myTypes)
{
if (myType.Active || form.SolutionType.Contains(myType.Value))
{
result.Add(myType);
}
}
// return sorted results
result.OrderBy(o => o.DisplayOrder);
return result;
}
Let me know if this isn't enough information. I think this requires more advanced language features that I'm just getting acquainted with. Maybe I should make them all use the same repository?
Thanks for your help.
EDIT:
Thanks for your help. I don't have any peer support, so this board is fantastic and I learned something from each of you. I wish I could accept all the answers.
You could firstly make your function a bit more terse like this:
private static IList<MyType> GetList(RequestForm form)
{
// get base list
IMyTypeRepository myTypeRepository =
new MyTypeRepository(new HybridSessionBuilder());
IList<MyType> myTypes = myTypeRepository.GetAll();
return myTypes.Where(x => x.Active || form.SolutionType.Contains(x.Value))
.OrderBy(x => x.DisplayOrder).ToList();
}
At that point, most of the content of the function is directly related to MyType, so how you can further improve it depends largely on how MyType relates to the other types involved. For example, here is a hypothetical version that you could write if your other types followed a reasonable-looking (to me) contract:
private static IList<T> GetList(RequestForm form) where T : OrderedValueContainer
{
// we'll want to somehow genericize the idea of a TypeRepository that can
// produce these types; if that can't be done, we're probably better off
// passing a repository into this function rather than creating it here
var repository = new TypeRepository<T>(new HybridSessionBuilder());
IList<T> myTypes = repository.GetAll();
// the hypothetical OrderedValueContainer class/interface
// contains definitions for Active, Value, and DisplayOrder
return myTypes.Where(x => x.Active || form.SolutionType.Contains(x.Value))
.OrderBy(x => x.DisplayOrder).ToList();
}
If all the types implement the same interface, (if they don't then make them, and make sure to add all the properties to the interface that are needed in this method) then you can do something like this:
private static IList<T> GetList(RequestForm form)
where T: IMyInterface
{
// get base list
IMyTypeRepository myTypeRepository = new MyTypeRepository(new HybridSessionBuilder());
IList<T> myTypes = myTypeRepository.GetAll();
// create results list
IList<T> result = new List<T>();
// iterate for active + used list items
foreach (T myType in myTypes)
{
if (myType.Active || form.SolutionType.Contains(myType.Value))
{
result.Add(myType);
}
}
// return sorted results
return result.OrderBy(o => o.DisplayOrder).ToList();
}
One other change I made is the last line, where you had the orderby on a seperate line and were never actually capturing the Ordered list.
EDIT: To solve the repository problem, you can have a repository factory of sorts that returns the correct repository based on the type of T:
public static IMyTypeRepository GetRepository(Type t)
{
if(t == typeof(Type1))
{
return Type1Repository();
}
if(t == typeof(Type2))
{
return Type2Repository();
}
.......
}
Assuming of course that all your repositories implement the IMyRepository interface.
First of all, all your types must implement a common interface that define properties like Active, Value ...
Also, for what I can tell, there must be a repository interface for all repositories independently of the MyType so that you can use a generic method like this. The GetAll() method should be defined in the IRepository.
public interface IRepository<T> where T : IMyType
{
IList<T> GetAll();
}
public class RepositoryFactory
{
public static IRepository<T> createRepository<T>(ISessionBuilder sb) where T : IMyType
{
// create repository
}
}
public interface IMyType
{
bool Active { get; }
string Value { get; }
}
private static IList<T> GetList(RequestForm form) where T : IMyType
{
// get base list
IRepository<T> repository = RepositoryFactory.createRepository<T>(new HybridSessionBuilder());
IList<T> myTypes = repository.GetAll();
// create results list
IList<T> result = new List<T>();
// iterate for active + used list items
foreach (T myType in myTypes)
{
if (myType.Active || form.SolutionType.Contains(myType.Value))
{
result.Add(myType);
}
}
// return sorted results
return result.OrderBy(o => o.DisplayOrder).ToList();
}
Assuming that the repositories share a common interface, the issue with the repository should be easy to fix: add a static function such as
public static IRepository RepositoryForType(Type t)
{
if(t == typeof(SomeClass))
return new SomeClassRepository(new HybridSession());
else if ...
else throw new InvalidOperationException("No repository for type " + t.Name);
}
This should require you the least amount of changes to your existing code, but mind that in the future you'll have to add classes support for new repositories in this function as you add new repositories in your project (if you're using unit testing you'll easily figure out if you forgot about this helper anyway).