tags:

views:

676

answers:

5

Exact Duplicate

C# Is String in Array

Im trying to find the easiest way to search a string for an array of possible strings. I know the easy way to do this for characters is to use myString.IndexOfAny(charArray). But how what if Id like to search my string for strings and not just characters? Are there any .net tricks or methods that make this easier?

Basically, Id like to do something like this:

string myName = "rahkim";
string[] names = new string[] {"joe","bob","chris"};

if(myName.IndexOfAny(names) >= 0)
{
      //success code//
}

I know there are ways to do this with loops, etc. But I was hoping for something inherent in the framework.

+2  A: 

Here's the right syntax:

if(names.Contains(myName))
{
      //success code//
}
Jose Basilio
I thought the OP wants to do substring matches.. or doesn't he ?
Gishu
I dont get 'Contains' as an option. I only get array methods when the intellisense pops up.
rahkim
Include Linq to get the extension - see duplicate question
daveb
I dont have Linq extension. Any other way to do this?
rahkim
+1  A: 
if (names.Contains(myName)) 
{
//success code//
}
TStamper
+5  A: 

You should define if you want to to find equal strings or search for a matching substring. Both ways are easy pre-LINQ and with LINQ.

string myName = "rahkim";
string[] names = new string[] { "joe", "bob", "chris" };
Equal Strings, LINQ
bool contains = names.Contains(myName);
Equal Strings, Pre-LINQ
bool contains = new List<string>(name).Contains(myName);
Substrings, LINQ
bool contains = names.Any(name => name.Contains(myName));
Substring, Pre-LINQ
bool contains = false;
foreach(string name in names)
  if (name.Contains(myName))
    contains = true;
Samuel
Thanks for these examples. I actually liked the "Equal Strings, Pre-LINQ" one, but it gave me an error - Argument '1': cannot convert from 'string[]' to 'string'. Im probably missing something here...
rahkim
+2  A: 

You can (also) use the static IndexOf method of the Array class.

bool hasName = Array.IndexOf(names, myName) > -1;
Pat
This seemed like the best fit. thanks.
rahkim
A: 

int IndexOfAny(String[] rgs) would indeed be nice but it's nominally an O(n^2) operation. If, in your application, the set of strings rgs is large and always the same, the most efficient approach is to load them into a trie data structure once, and then use the trie repeatedly to search for them within the unknown strings given at runtime.

Here is the relevant code, adapted from a C# trie source I found on the web, attributed to "Kerry D. Wong." In my version, each string in the trie has a "payload" of generic type TValue. To use this trie to simply search for substrings, the payload could always be set to true, as illustrated with *simple_trie*.

The other thing I changed here is that this trie automatically adapts allow for storage of arbitrary Unicode strings. The array at each node—which characterizes a trie—adjusts its base and length to accomodate the range of Unicode characters which need to be stored at that node. This allows for case-sensitive matching, for example.

The C# 3.0 initialization syntax is handy for this trie, but enabling it requires a dummy implementation of IEnumerable in order to compile. The CLR doesn't seem to call GetEnumerator() and I suggest that you don't try to enumerate with its result either.

using System;
using System.Collections.Generic;
using System.Linq;  // only used in Main()

class Program
{
    // trie with payload of type <String>
    static Trie<String> value_trie = new Trie<String>
    {
     { "rabbit", "cute" },
     { "giraffe", "tall" },
     { "ape", "smart" },
     { "hippo", "large" },
    };

    // degenerate case of a trie without payload
    static Trie<bool> simple_trie = new Trie<bool>
    {
     { "rabbit", true },
     { "giraffe", true },
     { "ape", true },
     { "hippo", true },
    };

    static void Main(String[] args)
    {
     String s = "Once upon a time, a rabbit met an ape in the woods.";

     // Retrieve payloads for words in the string.
     //
     // output:
     //      cute
     //      smart
     foreach (String word in value_trie.AllSubstringValues(s))
      Console.WriteLine(word);

     // Simply test a string for any of the words in the trie.
     // Note that the Any() operator ensures that the input is no longer
     // traversed once a single result is found.
     //
     // output:
     //      True
     Console.WriteLine(simple_trie.AllSubstringValues(s).Any(e=>e));

     s = "Four score and seven years ago.";
     // output:
     //      False
     Console.WriteLine(simple_trie.AllSubstringValues(s).Any(e => e));
    }
}

class TrieNode<TValue>
{
    private TrieNode<TValue>[] nodes = null;
    private TValue m_value = default(TValue);
    private Char m_base;

    public Char Base { get { return m_base; } }
    public bool IsEnd { get { return !m_value.Equals(default(TValue)); } }

    public TValue Value
    {
     get { return m_value; }
     set { m_value = value; }
    }

    public IEnumerable<TrieNode<TValue>> Nodes { get { return nodes; } }

    public TrieNode<TValue> this[char c]
    {
     get
     {
      if (nodes != null && m_base <= c && c < m_base + nodes.Length)
       return nodes[c - m_base];
      return null;
     }
    }

    public TrieNode<TValue> AddChild(char c)
    {
     if (nodes == null)
     {
      m_base = c;
      nodes = new TrieNode<TValue>[1];
     }
     else if (c >= m_base + nodes.Length)
     {
      Array.Resize(ref nodes, c - m_base + 1);
     }
     else if (c < m_base)
     {
      Char c_new = (Char)(m_base - c);
      TrieNode<TValue>[] tmp = new TrieNode<TValue>[nodes.Length + c_new];
      nodes.CopyTo(tmp, c_new);
      m_base = c;
      nodes = tmp;
     }

     TrieNode<TValue> node = nodes[c - m_base];
     if (node == null)
     {
      node = new TrieNode<TValue>();
      nodes[c - m_base] = node;
     }
     return node;
    }
};

class Trie<TValue> : System.Collections.IEnumerable
{
    private TrieNode<TValue> _root = new TrieNode<TValue>();

    // This dummy enables C# 3.0 initialization syntax
    public System.Collections.IEnumerator GetEnumerator()
    {
     return null;
    }

    public void Add(String s, TValue v)
    {
     TrieNode<TValue> node = _root;
     foreach (Char c in s)
      node = node.AddChild(c);

     node.Value = v;
    }

    public bool Contains(String s)
    {
     TrieNode<TValue> node = _root;
     foreach (Char c in s)
     {
      node = node[c];
      if (node == null)
       return false;
     }
     return node.IsEnd;
    }

    public TValue Find(String s_in)
    {
     TrieNode<TValue> node = _root;
     foreach (Char c in s_in)
     {
      node = node[c];
      if (node == null)
       return default(TValue);
     }
     return node.Value;
    }

    public IEnumerable<TValue> FindAll(String s_in)
    {
     TrieNode<TValue> node = _root;
     foreach (Char c in s_in)
     {
      node = node[c];
      if (node == null)
       break;
      if (node.Value != null)
       yield return node.Value;
     }
    }

    public IEnumerable<TValue> AllSubstringValues(String s)
    {
     int i_cur = 0;
     while (i_cur < s.Length)
     {
      TrieNode<TValue> node = _root;
      int i = i_cur;
      while (i < s.Length)
      {
       node = node[s[i]];
       if (node == null)
        break;
       if (node.Value != null)
        yield return node.Value;
       i++;
      }
      i_cur++;
     }
    }
};
Glenn Slayden