Простой способ поиска строки для строк - PullRequest
3 голосов
/ 23 апреля 2009

Я пытаюсь найти самый простой способ поиска string для массива возможных string с. Я знаю, что простой способ сделать это для персонажей - использовать myString.IndexOfAny(charArray). Но как, если я хотел бы искать в моих string string s, а не только символы? Существуют ли какие-либо хитрости или методы .net, которые делают это проще?

В принципе, я хотел бы сделать что-то вроде этого:

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

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

Я знаю, что есть способы сделать это с помощью циклов и т. Д. Но я надеялся на что-то присущее фреймворку.

Ответы [ 6 ]

10 голосов
/ 23 апреля 2009

Вы должны определить, хотите ли вы найти одинаковые строки или найти подходящую подстроку. Оба способа просты перед LINQ и с LINQ.

string myName = "rahkim";
string[] names = new string[] { "joe", "bob", "chris" };
Равные Строки, LINQ
bool contains = names.Contains(myName);
Равные строки, Pre-LINQ
bool contains = new List<string>(name).Contains(myName);
Подстроки, LINQ
bool contains = names.Any(name => name.Contains(myName));
Подстрока Pre-LINQ
bool contains = false;
foreach(string name in names)
  if (name.Contains(myName))
    contains = true;
8 голосов
/ 12 августа 2011

Если кто-то еще обнаружил это при попытке поиска метода .Net, такого как String.IndexOfAny (String []), это мое решение:

C #

public int IndexOfAny(string test, string[] values)
{
int first = -1;
foreach (string item in values) {
    int i = test.IndexOf(item);
    if (i >= 0) {
        if (first > 0) {
            if (i < first) {
                first = i;
            }
        } else {
            first = i;
        }
    }
}
return first;
}

VB

Public Function IndexOfAny(test As String, values As String()) As Integer
        Dim first As Integer = -1
        For Each item As String In values
            Dim i As Integer = test.IndexOf(item)
            If i >= 0 Then
                If first > 0 Then
                    If i < first Then
                        first = i
                    End If
                Else
                    first = i
                End If
            End If
        Next
        Return first
    End Function

Вы можете сделать LastIndexOfAny (String []), просто переключив

i < first 

до

i > first
5 голосов
/ 23 апреля 2009

Вы можете (также) использовать метод static IndexOf класса Array:

bool hasName = Array.IndexOf(names, myName) > -1;
3 голосов
/ 10 августа 2009

int IndexOfAny (String [] rgs) действительно было бы неплохо, но формально это операция O (n ^ 2). Если в вашем приложении набор строк rgs большой и всегда один и тот же, самый эффективный подход состоит в том, чтобы один раз загрузить их в структуру данных trie , а затем использовать три повторно искать их в неизвестных строках, заданных во время выполнения.

Вот соответствующий код, адаптированный из исходного кода C #, который я нашел в Интернете, приписываемого «Керри Д. Вонг». В моей версии каждая строка в дереве имеет «полезную нагрузку» общего типа TValue . Чтобы использовать этот набор для простого поиска подстрок, полезную нагрузку всегда можно установить на true , как показано на примере simple_trie .

Еще одна вещь, которую я здесь изменил, заключается в том, что этот набор автоматически адаптируется для хранения произвольных строк Юникода. Массив в каждом узле, который характеризует три, регулирует его основание и длину для соответствия диапазону символов Юникода, которые должны храниться в этом узле. Это позволяет учитывать регистр, например.

Синтаксис инициализации C # 3.0 удобен для этой процедуры, но для его включения требуется фиктивная реализация IEnumerable для компиляции. Кажется, что CLR не вызывает GetEnumerator (), и я предлагаю вам также не пытаться перечислять его результат.

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++;
        }
    }
};
2 голосов
/ 23 апреля 2009

Вот правильный синтаксис:

if(names.Contains(myName))
{
      //success code//
}
1 голос
/ 23 апреля 2009
if (names.Contains(myName)) 
{
//success code//
}
...