使用LINQ查询文本文件

3
我有一个简单的文本文件,其中包含一些CSV,具有以下结构:
@Parent1_Field1, Parent1_Field2, Parent1_Field3
Child1_Field1, Child1_Field2
Child2_Field1, Child2_Field2
...etc.
@Parent2_Field1, Parent2_Field2, Parent2_Field3
Child1_Field1, Child1_Field2
Child2_Field1, Child2_Field2
...etc.
'@' 表示一个父对象,其直接下方是子对象。(使用XML可以更好地表示这一点,但在我的情况下这不是一个选项。)
我的目的是使用LINQ查询此文件,而无需将其全部内容加载到内存中。首先,我创建了一个实现IEnumerable接口的类(在此处为MyCustomReader),其中我使用StreamReader获取文件的每一行。
例如,以下代码获取所有Parent对象(不包括子对象):
from line in MyCustomReader
where line.StartsWith("@")
select Parent.Create(line)

然而,当我想要创建涉及父对象和子对象的查询时,我遇到了麻烦。例如,获取特定父对象的所有子对象,或获取包含相同值的特定子字段的所有父对象。
例如,以下代码可以获取特定父对象的所有子对象:
public IEnumerable<Child> GetChildrenForAParent(string uniqueParentName)
{
    Parent parent = null;
    foreach (string line in MyCustomReader)
    {
        if (line.StartsWith("@"))
            parent = Parent.Create(line);
        else if (parent.UniqueName == uniqueParentName)
            yield return Child.Create(line);
    }
}

第二个例子:
public IEnumerable<Parent> GetParentsWhereChildHasThisValue(string childFiledValue)
{
    Parent parent = null;
    foreach (string line in MyCustomReader)
    {
        if (line.StartsWith("@"))
        {
            parent = Line.Create(line);
        }
        else //child
        {
            Child child = Child.Create(line);
            if (child.FiledValue == childFiledValue)
                yield return parent;
        }
    }
}

这两个例子如何使用LINQ实现?
1个回答

5
这并不美观,但对于第一个问题,以下内容应该可以解决:
MyCustomReader.SkipWhile(line => line != uniqueParentName).Skip(1).
                                     TakeWhile(line => !line.StartsWith("@"));

编辑:好的,我有点无聊。我认为这将为您完成第二个(但显然不适合LINQ解决的问题):

var res = MyCustomReader.Where(parentLine => parentLine.StartsWith("@"))
         .Join(MyCustomReader.Where(childLine => !childLine.StartsWith("@")),
              parentLine => parentLine,
              childLine => MyCustomReader.Reverse<string>()
                   .SkipWhile(z => z != childLine)
                   .SkipWhile(x => !x.StartsWith("@")).First(),
              (x, y) => new { Parent = x, Child = y })
         .Where(a => a.Child == childFiledValue).Select(a => a.Parent);

您将获得这些行,您可能需要在结尾处添加.Select(line => Child.Create(line))。 - Simon Fox
1
你可能需要为第二个找一个忍者 :) - Simon Fox

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接