2017-01-28 13 views
0

の部分文字列のList<string>を持っているか、大きなメインストリングに含まれていない可能性があります。例:私は何をしたいか部分文字列のリストで部分文字列が最初に出現するのを見つける方法は?

List<string> subStringList = new List<string>(){" at ", " @ "," near "," by "," above "}; 
List<string> searchStringList = new List<string>{ 
"GULF ISLAND POND NEAR LEWISTON, ME", 
"South Branch Raritan River near High Bridge NJ", 
"Susquehanna R near Browns Island at Dalmatia, PA", 
"PARKS CREEK AT LYLE FIELD RD NEAR JEFFERSON, GA", 
"HOMOSASSA R AT HOMOSASSA FL", 
"ST. CLAIR RIVER NEAR ROBERTS LANDING, MI" 
}; 

は、与えられた検索文字列に最初を発生subStringListの要素を検索し、そのポイントにsearchStringのを返すことです。例えば

:出力は次のようなものになるはずです

List<string> riverList = new List<string>(); 
foreach (var seachString in searchStringList) 
{ 
    string river = seachString.ToLower(); 
    int minIndex = int.MaxValue; 
    foreach (var subString in subStringList.Select(r => r.ToLower()).AsEnumerable()) 
    { 
     var index = river.IndexOf(subString); 
     if (index != null && index > -1 && index < minIndex) 
      minIndex = index; 
    } 
     riverList.Add(seachString.Substring(0,minIndex)); 
} 

[0]: "GULF ISLAND POND" 
[1]: "South Branch Raritan River" 
[2]: "Susquehanna R" 
[3]: "PARKS CREEK" 
[4]: "HOMOSASSA R" 
[5]: "ST. CLAIR RIVER" 

を私が持っているコードが動作するようですが、このような何かを行うには、より効率的な方法があり、どのようにこのような何かをLinqで行うことができますか?ここで

+0

私がしたいことは、指定された検索文字列の中で最初に出現した 'subStringList'の要素を見つけて、その点までsearchStringを返すことでしたか?" –

+0

はい、これは問題のより良い説明です。 –

+0

現在のコードでは、IndexOf(ss)がnullを返すことはないので、 'Index!= null'は不要です。また、検索している文字列に検索文字列がない場合は、現在のコードがクラッシュします。 – JohnG

答えて

2

String[]代わりのchar[]を取るString.IndexOfAny()ための過負荷を持っていいだろう。このことができますかどうかを確認、私はあなたが関連コメントで実装したコードを単純化している

searchStringList.Select(s => s.SubstringAsFarAsIndexOfAny(subStringList)); 


public static class stringExt 
{ 
    public static int IndexOfAny(this string s, IEnumerable<string> anyOf, StringComparison stringComparisonType=StringComparison.CurrentCultureIgnoreCase) 
    { 
     var founds= anyOf.Select(sub=> s.IndexOf(sub,stringComparisonType)).Where(i => i>=0); 
     return founds.Any() ? founds.Min() : -1; 
    } 

    public static string SubstringAsFarAsIndexOfAny(this string s, IEnumerable<string> anyOf, StringComparison stringComparisonType=StringComparison.CurrentCultureIgnoreCase) 
    { 
     var foundIndex= s.IndexOfAny(anyOf,stringComparisonType); 
     return foundIndex >=0 ? s.Substring(0, foundIndex) : s; 
    } 
} 
+0

私の理解では、StringComparison.OrdinalIgnoreCaseはより良い選択ですが、文化固有のアプリケーションを扱っていない限り、+1 –

+0

'が見つかりました。どれか() ? founds.Min() 'は2回列挙されます。これを防ぐには、本当に 'ToArray()'を追加するべきです。 – CSharpie

+0

しないでください。 Any()は列挙されず、Where()およびSelect()は配列、リストおよびイテレータの両方を最適化します。https://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs,4158286b17727025 –

0

は、LINQでそれを行う方法です:

var result = from str in searchStringList 
      from substr in subStringList 
      let index = str.IndexOf(substr, StringComparison.OrdinalIgnoreCase) 
      where index > -1 
      select str.Remove(index); 
+0

これは、入力行より多くの出力行を返します。 www.Linqpad.netはスニペットのテストに適しています:-) –

0

:ここでは私のもの

List<string> riverList = new List<string>(); 

    // Traverse through search string list 
    foreach (var searchString in searchStringList) 
    { 
     // Set the default min index value to -1 
     int minIndex = -1; 
     // Traverse through sub string list 
     foreach (var subString in subStringList) 
     { 
      // Fetch first index 
      var index = searchString.IndexOf(subString,StringComparison.OrdinalIgnoreCase); 

      // Reset Min Index logic 
      if(minIndex == -1) 
       minIndex = index; 
      else if(minIndex > index && index != -1) 
       minIndex = index; 

      // Break the processing of substrings if minindex is 0 (starting point) 
      if(minIndex == 0) 
      break; 
     }  

     riverList.Add(searchString.Substring(0, minIndex)); 
    } 
0

UPDATED(substringListで一致する部分文字列がある場合のための):ここに任意の拡張子なしのデフォルトLINQのメソッドと1弦ソリューションです:

var result = searchStringList 
       .Select(searchString => 
        searchString.Substring(0, 
         subStringList.Select(
           substring => searchString.IndexOf(substring, StringComparison.InvariantCultureIgnoreCase)) 
          .Where(s => s > -1)        
          .DefaultIfEmpty(0) 
          .Min())) 
          .Where(x => !string.IsNullOrEmpty(x));        
+0

検索された文字列が検索された文字列に含まれていない場合、クラッシュしないようにコードを記述できますか? – JohnG

+0

あなたが言及したケースのために更新されました –

+0

ありがとう、これはLINQを使用して期待どおりに動作するようです。検索された文字列が "@ ST。CLAIR RIVER ROBERTS LANDING、MI"のような文字列を要求している問題を解決する方法はありますか?あなたのコードはこれらの行を識別していないようです。 – JohnG

0

ループのために一般的なLINQの代替がAggregate()次のとおりです。

searchStringList.Select(s => s.SubstringAsFarAsIndexOfAny(subStringList)); 


public static class stringExt 
{ 
    public static int IndexOfAny(this string s, IEnumerable<string> anyOf, StringComparison stringComparisonType=StringComparison.CurrentCultureIgnoreCase) 
    { 
    var best = anyOf 
       .Select(sub => s.IndexOf(sub, stringComparisonType)) 
       .Aggregate(
         int.MaxValue, 
         (bestSoFar, current) => 0 <= current && current < bestSoFar ? current : bestSoFar 
        ); 
    return best == int.MaxValue ? -1 : best; 
    } 

    public static string SubstringAsFarAsIndexOfAny(this string s, IEnumerable<string> anyOf, StringComparison stringComparisonType=StringComparison.CurrentCultureIgnoreCase) 
    { 
     var foundIndex= s.IndexOfAny(anyOf,stringComparisonType); 
     return foundIndex >=0 ? s.Substring(0, foundIndex) : s; 
    } 
} 

私は、多くの人がこれをより読みやすいと思うとは思っていません。

関連する問題