【问题标题】:Using LINQ to query a text file使用 LINQ 查询文本文件
【发布时间】:2010-11-20 09:33:31
【问题描述】:

我有一个简单的文本文件,其中包含一些具有以下结构的 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)

但是,当我想创建涉及 Parent 和 Child 对象的查询时,我遇到了困难。例如,获取特定父对象的所有子对象或获取特定子字段包含相同值的所有父对象。

例如这将获取特定 Parent 对象的所有子对象:

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 实现这两个示例?

【问题讨论】:

    标签: c# linq csv text-files


    【解决方案1】:

    这不是很漂亮,但对于第一个来说,类似以下的东西应该可以工作:

    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)) 添加到末尾
    • 你可能需要为第二个找到忍者:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-31
    • 1970-01-01
    • 2014-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多