views:

298

answers:

3

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.

A: 

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");
Ricardo Villamil
One warning about using enums as keys: if you're using enums as dictionary keys, you might want to write an implementation of IEqualityComparer for it, in order to avoid unnecessary boxing. For more info (shameless plug): http://beardseye.blogspot.com/2007/08/nuts-enum-conundrum.html
Vojislav Stojkovic
+1  A: 

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);
        }
     }
BFree
+1  A: 

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