2016-05-03 58 views
2

我有一個具有各種屬性的.NET對象的集合。讓我們說它是一個遺傳密碼中的染色體鏈 - 儘管對象數據比這更復雜一點。我想在列表中搜索預定義的對象序列。我可以將對象定義爲有限數量的獨特感興趣類型。 R,B,d和一個巨大的名單,我想找到對象的特定序列:.NET對象列表中的正則表達式樣式匹配

一個大規模簡化版本是:

public class Chromosome { 
    public ChromosomeType CromosomeType { 
     get { 
     // Some logic that works out and returns the correct chromosome type 

     } 
    } 
} 

public enum ChromosomeType { 
    R, B, D 
} 

所以給大集合這些類型。我想匹配某些序列

例如, "R+B{3}D+"

所以在「正則表達式」以上,以下序列將在列表中匹配: RRRBBBDD

我需要能夠從一個很長的對象列表返回所有比賽。

顯然,正則表達式對此非常完美,但我實際上並沒有字符串,我有對象集合。

什麼是預定義序列搜索對象集合的最佳方法?

更新

科林的解決方案是我最後一個解決方案。它效果很好。我更新了它能夠處理多個匹配,並使用數組中爲了儘可能快地

下面是最終有效的解決方案:

public static class ChromosomesExtensions 
    { 
     public static IEnumerable<Chromosome[]> FindBySequence(this Chromosome[] chromosomes, string patternRegex) 
     { 
      var sequenceString 
       = String.Join(
        String.Empty, //no separator 
        (
         from c in chromosomes 
         select c.CromosomeType.ToString() 
        ) 
       ); 
      MatchCollection matches = Regex.Matches(sequenceString, patternRegex); 

      foreach (Match match in matches) 
      { 
       Chromosome[] subset = new Chromosome[match.Value.Length]; 

       var j = 0; 
       for (var i = match.Index; i < match.Index + match.Length; i++) 
       { 
        subset[j++] = chromosomes[i]; 
       } 
       yield return subset; 
      } 
     } 
    } 

    [TestFixture] 
    public class TestClass 
    { 
     [Test] 
     public void TestMethod() 
     { 
      var chromosomes = 
       new[] 
       { 
        new Chromosome(){ CromosomeType = ChromosomeType.D, Id = 1}, 
        new Chromosome(){ CromosomeType = ChromosomeType.R, Id = 2 }, 
        new Chromosome(){ CromosomeType = ChromosomeType.R, Id = 3 }, 
        new Chromosome(){ CromosomeType = ChromosomeType.B, Id = 4 }, 
        new Chromosome(){ CromosomeType = ChromosomeType.B, Id = 5 }, 
        new Chromosome(){ CromosomeType = ChromosomeType.B, Id = 6 }, 
        new Chromosome(){ CromosomeType = ChromosomeType.D, Id = 7 }, 
        new Chromosome(){ CromosomeType = ChromosomeType.D, Id = 8 }, 
        new Chromosome(){ CromosomeType = ChromosomeType.B, Id = 9 }, 
        new Chromosome(){ CromosomeType = ChromosomeType.R, Id = 10 }, 
        new Chromosome(){ CromosomeType = ChromosomeType.R, Id = 11 }, 
        new Chromosome(){ CromosomeType = ChromosomeType.B, Id = 12 }, 
        new Chromosome(){ CromosomeType = ChromosomeType.B, Id = 13 }, 
        new Chromosome(){ CromosomeType = ChromosomeType.B, Id = 14 }, 
        new Chromosome(){ CromosomeType = ChromosomeType.D, Id = 15 }, 
        new Chromosome(){ CromosomeType = ChromosomeType.D, Id = 16 }, 
        new Chromosome(){ CromosomeType = ChromosomeType.R, Id = 17 }, 
        new Chromosome(){ CromosomeType = ChromosomeType.R, Id = 18 }, 
        new Chromosome(){ CromosomeType = ChromosomeType.B, Id = 19 }, 
        new Chromosome(){ CromosomeType = ChromosomeType.B, Id = 20 }, 
        new Chromosome(){ CromosomeType = ChromosomeType.B, Id = 21 }, 
        new Chromosome(){ CromosomeType = ChromosomeType.D, Id = 22 }, 
        new Chromosome(){ CromosomeType = ChromosomeType.D, Id = 23 }, 
       }; 

      var matchIndex = 0; 
      foreach (Chromosome[] match in chromosomes.FindBySequence("R+B{3}D+")) 
      { 
       Console.WriteLine($"Match {++matchIndex}"); 
       var result = new String(match.SelectMany(x => string.Join("", $"id: {x.Id} Type: {x.CromosomeType.ToString()}\n")).ToArray()); 
       Console.WriteLine(result); 
      } 

     } 
    } 

輸出:

Match 1 
id: 2 Type: R 
id: 3 Type: R 
id: 4 Type: B 
id: 5 Type: B 
id: 6 Type: B 
id: 7 Type: D 
id: 8 Type: D 

Match 2 
id: 10 Type: R 
id: 11 Type: R 
id: 12 Type: B 
id: 13 Type: B 
id: 14 Type: B 
id: 15 Type: D 
id: 16 Type: D 

Match 3 
id: 17 Type: R 
id: 18 Type: R 
id: 19 Type: B 
id: 20 Type: B 
id: 21 Type: B 
id: 22 Type: D 
id: 23 Type: D 
+0

我不是很清楚。是否有一個屬性保存了您匹配的值,或者您想對類型名稱本身應用正則表達式。你能用你的對象結構更新問題嗎? – niksofteng

+0

假設我的理解正確,你可以重寫'ToString()'來讓它返回,無論這個特定對象是R,B還是D.然後,爲整個鏈建立一個字符串,然後在你的'Regex'上執行那。 – AntiTcb

+0

你的對象的例子會有所幫助。 – DVK

回答

2

一簡單,乾淨的方式使用擴展方法(實際上支持通過Regex搜索)。

類:

public static class ChromosomesExtensions 
{ 
    public static IEnumerable<Chromosome> FindBySequence(this IEnumerable<Chromosome> chromosomes, string patternRegex) 
    { 
     var sequenceString 
      = String.Join(
       String.Empty, //no separator 
       (
        from c in chromosomes 
        select c.CromosomeType.ToString() 
       ) 
      ); 
     var match = Regex.Match(sequenceString, patternRegex); 
     //returns empty if no match is found 
     return chromosomes.ToList().GetRange(sequenceString.IndexOf(match.Value), match.Value.Length); 
    } 
} 

用法:

var chromosomes = 
    new[] 
    { 
     new Chromosome(){ CromosomeType = ChromosomeType.D }, 
     new Chromosome(){ CromosomeType = ChromosomeType.R }, 
     new Chromosome(){ CromosomeType = ChromosomeType.R }, 
     new Chromosome(){ CromosomeType = ChromosomeType.B }, 
     new Chromosome(){ CromosomeType = ChromosomeType.B }, 
     new Chromosome(){ CromosomeType = ChromosomeType.B }, 
     new Chromosome(){ CromosomeType = ChromosomeType.D }, 
     new Chromosome(){ CromosomeType = ChromosomeType.D }, 
     new Chromosome(){ CromosomeType = ChromosomeType.B }, 
    }; 

var queryResult = chromosomes.FindBySequence("R+B{3}D+"); 
+0

這將返回具有Prop = R | B | D的單個對象。但是我想要一系列符合模式的對象。 – reach4thelasers

+0

啊,我明白了。我只是撇清你的問題。我會調整答案。 – Colin

+0

我用一個例子加強了這個問題 – reach4thelasers

1

Colin's answer似乎讓你接近,你想要的。我有兩個想法補充:

  1. 你真的需要拉「RegEx」來完成任務嗎?您正在爲量詞使用RegEx庫的一個子集,但這是以增加依賴到複雜工具爲代價的。如果您只是製作自己的簡單(儘管不太靈活)的語法,您可能會擁有更便攜的應用程序。

  2. 我會考慮避免ToString,並簡單地給你的對象一個const字符串屬性,你可以用它來反彈RegEx。如果你正在處理大量的數據,那麼在任何地方調用ToString()都會給你帶來不小的開銷。

+1

有效的點數。我的代碼當然是爲了簡單而不是性能優化的,但我應該注意到FindBySequence()在我的本地開發箱中花費大約0.6秒時間來爬行一百萬條染色體(如果您開始使用char和enum)。我不確定OP有什麼樣的性能或規模要求,但是我的經驗法則是如果真實世界的影響可以忽略不計,那麼選擇簡單而不是性能。另外,我不確定OP是否說正則表達式是一個需求,我只是用它來使查詢易於構造/理解。 – Colin

1

也許爲時已晚,但我必須回答。我實現了ORegex引擎(不是爲了你的問題,而是非常接近你的問題)。 它的用法與您使用正則表達式非常相似,並且可以完美地解決您在任意收集時使用模式匹配的問題。它比上面的方法快得多,甚至可以傳遞一些非常複雜的條件函數(例如,也檢查一些對象屬性)。它完全免費且可通過Nuget獲得。

實例總理序列:有更多的例子 How to search patterns in arbitrary sequences?

項目頁面:https://github.com/eocron/ORegex