tags:

views:

37

answers:

4

Hi,

I currently have an arraylist containing classes in C#. The arraylist is filled like this:

 foreach (XmlElement Path in locaties)
                    {


                        ISoundSource track = engine.AddSoundSourceFromFile(Path.InnerXml);

                        mixarray.Add(track);

                    }

then the array has many ISoundSource classes as its items. Now the thing that sets them apart in the array is their 'name' property. Later on I want to get the ISoundSource from the array by doing a search. I looked up on how to search arraylists and it is said to use a binarysearch but I don't see a way to look up an object with a certain property. How can I get the item from the array which has the name I specify?

+1  A: 

You should probably use a Dictionary<,> as it will be much easier to maintain. Also, you should use List<> instead of ArrayList. If you must use BinarySearch, you will have to pass it a custom implementation of IComparer in order to have it use the Name property. Here's an example with a dictionary:

var dictionary = new Dictionary<string, ISoundSource>();
foreach (XmlElement Path in locaties)
{
    ISoundSource track = engine.AddSoundSourceFromFile(Path.InnerXml);
    mixarray.Add(track);
    dictionary[track.Name] = track;
}

ISoundSource item = dictionary["MyTrackName"];
Kirk Woll
internetmw
A `Dictionary` won't preserve the order of addition/insertion or the order of the keys. Also, it will fail if multiple items have the same key. Those may or may not be relevant limitations in this case.
Robert Rossney
This also assumes the OP is using .NET 2.0 or newer. If such an assumption can be made, why not assume that they are using .NET 3.5 and use Linq?
Phil Gilmore
Robert, The dictionary won't preserve the order, which is why "mixarray" was left in there. In my own code, I have a generic version of OrderedDictionary in my own class library. Since the OP requested lookup by key, I believe uniqueness is implied.Phil, I always prefer LINQ solutions instead of loops, but he wants the means to obtain an ISoundSource by Name efficiently at any point in his code. If you are content with O(N) time for lookups, then LINQ would be fine.
Kirk Woll
A: 

Check out the two parameter overload of BinarySearch which takes an IComparer as the second parameter - you then need to create a small class that inherits from IComparer that will compare the names of two of your Track objects, and pass an instance of this comparer into the BinarySearch.

Will A
Thanks for the fast response, although Kirk seems to have something very elegant :-)
internetmw
A: 

There are many ways to do what you're asking for, and the right way depends on information that you haven't provided:

  • Does the Name property uniquely identify items?
  • Does every item have a Name?
  • Does the match have to be exact?
  • Is it important to know what order the items were originally added to the list in, i.e. the order that they appear in the source XML?
  • Are you trying to find items given their Name, or access them in order by their Name?
  • How important is it that this be efficient?

It may be that the right solution is to simply use LINQ to find an item:

ISoundSource track = mixarray
   .Cast<ISoundSource>
   .Where(x => x.Name == name)
   .FirstOrDefault();

which will set track to the first item in the list whose name matches the value you're looking for, and to null if there's no match found. (If you use a List<ISoundSource> instead of an ArrayList, you can omit the Cast<ISoundSource> - one of many, many reasons to use List<T> over ArrayList in most cases.)

Most of the time I'll use a Dictionary<TKey, TValue> for this kind of thing, but that's because most the time the answers to those questions are yes, yes, yes, no, don't care about the order, pretty important.

Robert Rossney
A: 

For posterity, here is an alternative way to generate a dictionary using a simple Linq expression.

var dictionary = locaties
    .Select(p->engine.AddSoundSourceFromFile(Path.InnerXml))  
    .ToDictionary(t->t.Name);

The .Select() transforms each node into an ISoundSource. When done, a collection (IEnumerable of ISoundSource) is returned. The .ToDictionary() then converts that list of ISoundSource to a Dictionary of string, ISoundSource.

This requires .NET Framework 3.5 or higher.

Phil Gilmore