【发布时间】:2016-05-03 14:52:57
【问题描述】:
我有一组具有各种属性的 .NET 对象。可以说它是遗传密码中的一串染色体——尽管对象数据比这要复杂一些。我想在列表中搜索预定义的对象序列。我可以将对象定义为有限数量的唯一感兴趣类型。 R,B,D 并且在一个庞大的列表中我想找到某些对象序列:
一个大大简化的版本是:
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
我需要能够从很长的对象列表中返回所有匹配项。
显然正则表达式非常适合这个,但我实际上没有字符串,我有对象的集合。
在对象集合中搜索预定义序列的最佳方法是什么?
更新
Colin 的解决方案是我最终采用的解决方案。它工作得很好。我对其进行了更新,使其能够处理多个匹配项,并使用数组以尽可能快
这是最终的工作解决方案:
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
【问题讨论】:
-
我不太清楚。是否有一个属性包含您要匹配的值,或者您想在类型名称本身上应用正则表达式。你能用你的对象结构更新问题吗?
-
假设我理解正确,您可以覆盖
ToString()让它返回该特定对象是 R、B 还是 D。然后,为整个链构建一个字符串,然后执行你的Regex。 -
您的对象的示例会有所帮助。
-
我加了一个类型的例子
-
@AlexGravely 我想到了这一点,但如果可能的话,我想避免遍历集合并构建字符串。但是,是的,这可能是最有效的方式。除非有办法让对象集合在正则表达式类中看起来像一个字符串?