I have a List of a "complex" type - an object with a few string properties. The List itself is a property of another object and contains objects of a variety of types, as shown in this abbreviated class structure:
Customer {
public List<Characteristic> Characteristics;
.
.
.
}
Characteristic {
public string CharacteristicType;
public string CharacteristicValue;
}
I'd like to be able to collect a List of the values of a given type of Characteristics for the current Customer, which I can do in a 2-step process as follows:
List<Characteristic> interestCharacteristics = customer.Characteristics.FindAll(
delegate (Characteristic interest) {
return interest.CharacteristicType == "Interest";
}
);
List<string> interests = interestCharacteristics.ConvertAll<string>(
delegate (Characteristic interest) {
return interest.CharacteristicValue;
}
);
That works fine, but it seems like a long way around. I'm sure I must be missing a simpler way of getting to this list, either by chaining together the FindAll() and Convert() methods, or something else I'm overlooking entirely.
For background, I'm working in .Net 2.0, so I'm limited to the .Net 2 generics, and the Characteristic class is an external dependency - I can't change it's structure to simplify it, and there are other aspects of the class that are important, just not in relations to this problem.
Any pointers or additional reading welcomed.
Here's a generator implementation
public static IEnumerable<string> GetInterests(Customer customer)
{
foreach (Characteristic c in customer.Characteristics)
{
if (c.CharacteristicType == "Interest")
yield return c.CharacteristicValue;
}
}
sadly 3.5 extension methods and lambda are out based on your requirements but for reference here's how to do it:
customer.Characteristics
.Where(c => c.CharacteristicType == "Interest")
.Select(c => c. CharacteristicValue);
I would do some of the work manualy. By doing a FindAll first, and then a Convert, you're looping through your collection twice. It doesn't seem neccessary. If all you want at the end of the day, is a List of CharacteristicValue then just loop through your original collection, and add the CharacteristicValue to a List of each one that matches your criteria. Something like this:
Predicate<Characteristic> criteria = delegate (Characteristic interest)
{
return interest.CharacteristicType == "Interest";
};
List<string> myList = new List<string>();
foreach(Characteristic c in customer.Characteristics)
{
if(criteria(c))
{
myList.Add(c.CharacteristicValue);
}
}
Why not create a Dictionary<string, List<string>>, that way you can add "Interest" as the key, and a list of values as the value. For example:
Customer {
public Dictionary<string, List<string>> Characteristics;
.
.
.
}
...
Characteristics.Add("Interest", new List<string>());
Characteristics["Interest"].Add("Post questions on StackOverflow");
Characteristics["Interest"].Add("Answer questions on StackOverflow");
..
List<Characteristic> interestCharacteristics = Characteristics["Interest"];
Furthermore, if you wanted, you could limit your characteristics to a list of possible values by making it an enum, then use that as the data type of your dictionary's key:
public enum CharacteristicType
{
Interest,
Job,
ThingsYouHate
//...etc
}
then declare your dictionary as:
public Dictionary<CharacteristicType, List<string>> Characteristics;
..
Characteristics.Add(CharacteristicType.Interest, new List<string>());
Characteristics[CharacteristicType.Interest].Add("Post questions on StackOverflow");
Characteristics[CharacteristicType.Interest].Add("Answer questions on StackOverflow");
Related
I am trying to determine the cleanest (it's good enough if it can be understood easily) way to determine which actions to execute given a list of tuples.
Let's say I have the table MyType and the table MyAction. These tables are joined by a middle table ActionsPerType, since MyType has a many-to-many relationship to MyAction.
Now, the idea is to execute the actions ActionsPerType declares, for example:
Dictionary<int, int> actionsPerType = context.ActionsPerType
.GroupBy(c => c.MyTypeId)
.ToDictionary(c => c.Key.MyTypeId, c.ToList());
I want to convert this to a Dictionary<int, Func<Task<decimal>>> where the Key is the actionsPerType.Key and the Value is a list of async Task<decimal> defined in the code.
Is there any cleaner approach to this than something like (done here, untested):
foreach (var item in actionsPerType)
{
switch ((MyTypeEnum)item.Key)
{
case MyTypeEnum.Random:
{
foreach (var action in actionsPerType[MyTypeEnum.Random])
{
switch ((MyActionEnum)action)
{
case MyActionEnum.Random:
dictionary[MyTypeEnum.Random].Add(SomeTaskThatReturnsBool);
break;
}
}
}
}
}
MyTypeEnum would hold around 10 items while MyActionEnum would hold near 25, so this would be really long and ugly.
Personally I'm a big fan of Attributes. I'm not entirely sure of the desired outcome and if the following suits your situation, but here goes.
Because enums are considered constants, they can be used inside attribute parameters. Therefore the following is possible:
public enum TypeEnum{
T1,T2
}
public enum ActionEnum{
A1,A2
}
public static class SomeClass
{
[TypeAction(TypeEnum.T1, ActionEnum.A1)]
public static void Foo(){
}
[TypeAction(TypeEnum.T1, ActionEnum.A2)]
[TypeAction(TypeEnum.T2, ActionEnum.A2)] //<-- example of method can be used for multiple types/actions
public static void Bar(){
}
}
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] // <- AllowMultiple in case an action can be used multiple times
public class TypeActionAttribute:Attribute
{
public TypeActionAttribute(TypeEnum type, ActionEnum action)
{
this.Type=type;
this.Action = action;
}
public TypeEnum Type{get;set;}
public ActionEnum Action{get;set;}
}
Once the attribute-class is created, each enum combi can be assigned to any method. Obtaining all methods can be done in runtime (preferable once during initialization and memoized).
Probably a list of possible combinations is most useful in the long run, but your example seems to need only the TypeEnum with all methods (ActionEnum is not stored in the pseudecode), which would be equivalent in something like:
var typeMethods = (from m in typeof(SomeClass).GetMethods() //the methods are probably based in multiple types. Depending where they can be found, the types of an Assembly can be queried
from a in m.GetCustomAttributes(typeof(TypeActionAttribute), true)
group m by ((TypeActionAttribute)a).Type)
.ToDictionary(gr=>gr.Key, gr=>gr.ToList());
typemethods will be a dictionary of TypeEnum with lists of methodinfo's. (The methodinfos can be invoked or processed to specific lambdas)
I really like the answer given by #Me.Name. However if for some weird reason Attributes are not a choice why not use a dictionary of tasks:
Dictionary<MyActionEnum, Func<Task<decimal>>> tasks = new Dictionary<MyActionEnum, Func<Task<decimal>>> {
{ MyActionEnum.A1, __Task1 },
{ MyActionEnum.A2, __Task2 },
{ MyActionEnum.A3, __Task3 },
{ MyActionEnum.A4, __Task4 },
{ MyActionEnum.A5, async () => { return await Task.Delay(5000).ContinueWith(result => new Decimal(16)); } }
};
static async Task<decimal> __Task1() { return await Task.FromResult<decimal>(new Decimal(420)); }
// etc
IF I understand your requirements then this should fit neatly with linq, and I suppose an advantage here is that the dictionary allows for runtime dynamics.
I have a generic list which I want to order by two properties, priority and then by description to fill a drop down list.
I know that when I now exactly the type of the object list I can do
list = list.Orderby(x=>x.property1).ThenOrderBy(x=>x.property2).
My question is how can I check if the property1 and property2 exist on the object and then sort my list based on those properties.
Because you are using a generic list, the compiler will check that for you.
For example: if you write code like
List<Object> list = new List<Object>();
var newlist = list.Orderby(x=>x.property1).ThenOrderBy(x=>x.property2);
you'll get a compiler error on property1 & property2 because the compiler won't find these properties on the Object type.
If you want to support different types that each should have those 2 properties, the correct way would be to create an interface with those 2 properties, let each of the types you want to support implement that interface and then use a constraint on T like Arturo proposed.
Something like
interface ICanBeSorted
{
string property1 {get;}
string property2 {get;
}
public List<T> MySortMethod(List<T> list) where T : ICanBeSorted
{
return list.OrderBy(x=>x.property1).ThenOrderBy(x=>x.property2);
}
This method will be able to sort all types that implement interface ICanBeSorted.
You can wrap the selector in a try-catch block :
Func<dynamic, dynamic> DynamicProperty(Func<dynamic, dynamic> selector)
{
return x =>
{
try
{
return selector(x);
}
catch (RuntimeBinderException)
{
return null;
}
};
}
Usage :
var sorted = list
.OrderBy(DynamicProperty(x => x.property1))
.ThenBy(DynamicProperty(x => x.property2));
well, the way you are trying to do it is a bad idea. Try using if-else or switch case first and then put your code to order them the way you want accordingly.
Say I have a list of objects, object Fruit. Fruit has a property Name. i.e. Fruit1.Name = "Apple", Fruit2.Name = "Orange", Fruit3.Name = "Apple", Fruit4.Name = "Melon"... etc
List<Fruit> Basket = {Fruit1, Fruit2, Fruit3, Fruit4, Fruit 5...... Fruit 100}.
I want to have a list of Unique Fruits, where every fruit in the list has unique name. I want to optimize for time.
I've seen some people do the following. Is this a best way?
public List<Fruit> GetUniqueFruits(List<Fruit> Basket)
{
Dictionary<string, Fruit> tempUniqueFruits = new Dictionary<string, Fruit>();
List<Fruit> uniqueFruits = new List<Fruit>();
foreach(var fruit in Basket)
{
if (!tempUniqueFruits.ContainsKey(fruit.Name)
{
tempUniqueFruits.Add(fruit.Name, fruit);
uniqueFruits.Add(fruit);
}
}
return uniqueFruits;
}
I hear dictionary lookup is very fast, so I guess maybe that's why this is used, but I want to know if there is a better way.
Thanks matt burland, i fixed the typo. ( coulnd't comment yet)
You can use an IEqualityComparer to clarify the code.
public List<Fruit> GetUniqueFruits(List<Fruit> Basket) {
var set = new HashSet<Fruit>(Basket, new FruitNameEqualityComparer());
return set.ToList();
}
public class Fruit {
public string Name { get; set; }
public DateTime RipeTime { get; set; }
}
class FruitNameEqualityComparer : IEqualityComparer<Fruit> {
public int Compare(Fruit a, Fruit b) {
return a.Name.CompareTo(b.Name);
}
public bool Equals(Fruit a, Fruit b) {
return a.Name.Equals(b.Name);
}
public int GetHashCode(Fruit f) {
return f.Name.GetHashCode();
}
}
Dictionary<T, U> is best used when you are mapping from keys to values, but if you are only interested in maintaining a set of unique values without any mappings, a HashSet<T> is specifically designed for that purpose.
A dictionary forces the code to make sure that it only contains unique keys, not values. So if you try to add another key that already exists it will throw an error. When wanting to grab a value you just have to get it by the key name which the dictionary does a lookup using a hash, which makes it very very fast. When wanting to search the list you have to iterate the whole list to find the one you want which can be slow as you are iterating the whole list.
A shorter way would be:
return Basket.GroupBy(f => f.Name).Select(grp => grp.First()).ToList();
although this might not keep the first item in Basket with the given name.
So if the names are the unique part of the object (i.e. the key) and the order of the items isn't important, then a Dictionary<string, Fruit> is a perfectly valid way to store them. Another option would be HashSet, but then you'd need to implement Equals and GetHashCode in your Fruit class (or create a IEqualityComparer<Fruit>).
But for you specific code, there are Linq statements you can use (like Lee's) which are efficient, but with your particular code, you don't need to keep create a list of unique items at the same time as you are building your dictionary (unless the order is important) because your can return tempUniqueFruits.Values.ToList()
Also, if you want to build the list of unique items (to preserve the order), then since you are not actually using the values in the dictionary, just the keys, you could use a HashSet<string> instead.
I apologize upfront, because I now realize that I have completely worded my example wrong. For those who have given responses, I truly appreciate it. Please let me re-attempt to explain with a more accurate details. Please edit your responses, and once again, I apologize for not being more exact in my previous posting.
Using an entity framework model class called Staging (which is a representation of my Staging table), I have the following List<Staging>.
List<Staging> data = (from t in database.Stagings select t).ToList();
//check for an empty List...react accordingly...
Here is a quick look at what Staging looks like:
public partial class Staging
{
public int ID { get; set; } //PK
public int RequestID { get; set; } //FK
...
public string Project { get; set; }
...
}
Let us suppose that the query returns 10 records into my data list. Let us also suppose that data[3], data[6], and data[7] each have the same value in data.Project, let's say "Foo". The data.Project value is not known until runtime.
Given this, how would I keep the first occurrence, data[3], and remove data[6] and data[7] from my List<Staging>?
Edit:
I have the following code that works, but is there another way?
HashSet<string> projectValuesFound = new HashSet<string>();
List<Staging> newData = new List<Staging>();
foreach (Staging entry in data)
{
if (!projectValuesFound.Contains(entry.Project))
{
projectValuesFound.Add(entry.Project);
newData.Add(entry);
}
}
You can do this via LINQ and a HashSet<T>:
var found = new HashSet<string>();
var distinctValues = theList.Where(mc => found.Add(mc.Var3));
// If you want to assign back into the List<T> again:
// theList = distinctValues.ToList();
This works because HashSet<T>.Add returns true if the value was not already in the set, and false if it already existed. As such, you'll only get the first "matching" value for Var3.
var uniques = (from theList select theList.Var3).Distinct();
That will give you distinct values for all entries.
You could use Linq:
var result = (from my in theList where my.Var3 == "Foo" select my).First();
If you also want to keep the other items, you can use Distinct() instead of First(). To use Dictinct(), either MyClass must implement IEquatable<T>, or you must provide an IEqualityComparer<T> as shown in the MSDN link.
The "canonical" way to do it would be to pass appropriately implemented comparer to Distinct:
class Var3Comparer : IEqualityComparer<MyClass> {
public int GetHashCode(MyClass obj) {
return (obj.Var3 ?? string.Empty).GetHashCode();
}
public bool Equals(MyClass x, MyClass y) {
return x.Var3 == y.Var3;
}
}
// ...
var distinct = list.Distinct(new Var3Comparer());
Just beware that while current implementation seems to keep the ordering of the "surviving" elements, the documentation says it "returns an unordered sequence" and is best treated that way.
There is also a Distinct overload that doesn't require a comparer - it just assumes the Default comparer, which in turn, will utilize the IEquatable<T> if implemented by MyClass.
I have asked this question about using the a Linq method that returns one object (First, Min, Max, etc) from of a generic collection.
I now want to be able to use linq's Except() method and I am not sure how to do it. Perhaps the answer is just in front on me but think I need help.
I have a generic method that fills in missing dates for a corresponding descriptive field. This method is declared as below:
public IEnumerable<T> FillInMissingDates<T>(IEnumerable<T> collection, string datePropertyName, string descriptionPropertyName)
{
Type type = typeof(T);
PropertyInfo dateProperty = type.GetProperty(datePropertyName);
PropertyInfo descriptionProperty = type.GetProperty(descriptionPropertyName);
...
}
What I want to accomplish is this. datePropertyName is the name of the date property I will use to fill in my date gaps (adding default object instances for the dates not already present in the collection). If I were dealing with a non-generic class, I would do something like this:
foreach (string description in descriptions)
{
var missingDates = allDates.Except(originalData.Where(d => d.Description == desc).Select(d => d.TransactionDate).ToList());
...
}
But how can I do the same using the generic method FillInMissingDates with the dateProperty and descriptionProperty properties resolved in runtime?
I think the best way would be to define an interface with all of the properties that you want to use in your method. Have the classes that the method may be used in implement this interface. Then, use a generic method and constrain the generic type to derive from the interface.
This example may not do exactly what you want -- it fills in missing dates for items in the list matching a description, but hopefully it will give you the basic idea.
public interface ITransactable
{
string Description { get; }
DateTime? TransactionDate { get; }
}
public class CompletedTransaction : ITransactable
{
...
}
// note conversion to extension method
public static void FillInMissingDates<T>( this IEnumerable<T> collection,
string match,
DateTime defaultDate )
where T : ITransactable
{
foreach (var trans in collection.Where( t => t.Description = match ))
{
if (!trans.TransactionDate.HasValue)
{
trans.TransactionDate = defaultDate;
}
}
}
You'll need to Cast your enumeration to ITransactable before invoking (at least until C# 4.0 comes out).
var list = new List<CompletedTransaction>();
list.Cast<ITransactable>()
.FillInMissingDates("description",DateTime.MinValue);
Alternatively, you could investigate using Dynamic LINQ from the VS2008 Samples collection. This would allow you to specify the name of a property if it's not consistent between classes. You'd probably still need to use reflection to set the property, however.
You could try this approach:
public IEnumerable<T> FillInMissingDates<T>(IEnumerable<T> collection,
Func<T, DateTime> dateProperty, Func<T, string> descriptionProperty, string desc)
{
return collection.Except(collection
.Where(d => descriptionProperty(d) == desc))
.Select(d => dateProperty(d));
}
This allows you to do things like:
someCollection.FillInMissingDates(o => o.CreatedDate, o => o.Description, "matching");
Note that you don't necessarily need the Except() call, and just have:
.. Where(d => descriptionProperty(d) != desc)
foreach (string description in descriptions)
{
var missingDates = allDates.Except<YourClass>(originalData.Where(d => d.Description == desc).Select(d => d.TransactionDate).ToList());
}
In fact, almost all LINQ extension in C# have a generic possible value. (Except and Except)
If you're going to identify the property to be accessed by a string name, then you don't need to use generics. Their only purpose is static type safety. Just use reflection to access the property, and make the method work on a non-generic IEnumerable.
Getting Except result with multiple properties working with custom data class is not allowed.
You have to use it like this: (given in msdn 101 LINQ Samples)
public void Linq53()
{
List<Product> products = GetProductList();
List<Customer> customers = GetCustomerList();
var productFirstChars =
from p in products
select p.ProductName[0];
var customerFirstChars =
from c in customers
select c.CompanyName[0];
var productOnlyFirstChars = productFirstChars.Except(customerFirstChars);
Console.WriteLine("First letters from Product names, but not from Customer names:");
foreach (var ch in productOnlyFirstChars)
{
Console.WriteLine(ch);
}
}
Having the key, you can handle your data accordingly :)