Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / programming / string

Dictionary<string,T>.BestMatch

4.60/5 (3 votes)
27 Mar 2015CPOL1 min read 33.1K  
Extension methods to select a Dictionary entry using StartsWith

Introduction

I present here two extension methods that allow me to select an item from a Dictionary even if I have only the first part of the key, rather than the whole key.

Background

A few times in the past year, I wanted to select an entry in a Dictionary<string,T> based on only the first part of the key. In early attempts, I added each portion separately; for example if I had a key of "YES", I would also add "Y" and "YE". This became unwieldy as the keys became longer and the benefits of hashing didn't seem as crucial. However, I didn't want to depart from using a Dictionary entirely.

Adding the use of A String.StartsWith that uses a StringComparer[^] to a Dictionary was simple.

The Code

BestMatch will attempt the usual ContainsKey first and only resort to iterating the keys and using StartsWith if the full string isn't found. If it does have to iterate, then it can't stop as soon as it finds a match, it must continue in case it finds a second match.

public static T
BestMatch<T>
(
  this System.Collections.Generic.Dictionary<string,T> Source
,
  string                                               String
)
{
  T result = default(T) ;

  if ( Source.ContainsKey ( String ) )
  {
    result = Source [ String ] ;
  }
  else
  {
    bool found = false ;

    foreach ( string s in Source.Keys )
    {
      if ( s.StartsWith ( String , Source.Comparer ) )
      {
        if ( found )
        {
          throw ( new System.ArgumentException ( "Ambiguous name" , String ) ) ;
        }

        result = Source [ s ] ;

        found = true ;
      }
    }

    if ( !found )
    {
      throw ( new System.ArgumentException ( "Unrecognized name" , String ) ) ;
    }
  }

  return ( result ) ;
}

The second method works similarly to TryParse in that it returns a boolean and the value (or the default for the type) is passed back via an out parameter. If you want to change the name to TryBestMatch or HasBestMatch or something, go ahead.

public static bool
BestMatch<T>
(
  this System.Collections.Generic.Dictionary<string,T> Source
,
  string                                               String
,
  out T                                                Value
)
{
  bool result = true ;

  Value = default(T) ;

  try
  {
    Value = BestMatch ( Source , String ) ;
  }
  catch
  {
    result = false ;
  }

  return ( result ) ;
}

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)