0

我有一个很大的文件(> 1GB),它是用管道分隔的。我想使用 file.readlines 查询文件,分割每一行,根据索引列表从分割的行中选择特定元素(我将提供索引数组)并将其返回到自定义类型类对象的字典。

目前我有这个:

strIndexes = "1,3,5,7";
var selected = strIndexes.Split(',')
                         .Select(x => int.Parse(x))
                         .Select(index => File.readlines(myFile)
                         .Select(x => split('|')[index]).toArray();

但是,此查询由索引引导,效率不高。它返回 4 个向量,每个向量对应上例中指定的 4 个索引。

我将不胜感激任何帮助。

更新:

谢谢大家的评论。我正在添加一些示例数据。文件数据如下所示:

Line1: aa|ab|de|gt|hj|de|fr|gt|hy // Header
Line2: sd|12|f4|tr|hj|df|ds|e3|12
Line3: 34|fd|3d|35|df|45|dq|32|dd
.
.
.
Line N 34|df|f3|df|33|s2|23|df|44

N = 数百万行。数据格式仅用于示例目的,每个单元格包含不同长度和结构的字符串。

现在,用户以标题列名称的形式输入他想要的请求数据,例如:ab,de,fr,hy,我解析并理解我需要列 2,3,7 和 9。现在我想解析文件并返回一个对象,其中每个条目都是一个字典条目,它表示一行中的数据,其中包含一个键(它是列数据之一)和一个值,它是标记化数据的 string[]。

因此,假设对于此示例,我希望数据按第 7 列排序,因此最终的 dict 将是:

[ds]->[12,f4,12]
[dq]->[fd,3d,dd]
.
.
.
[23]->[df,f3,44]
4

4 回答 4

0

我建议编写自己的标记器(或找到一个),您可以使用String.IndexOfAny并搜索“|” 或“,”,构建您自己的状态机来告诉它在哪里扑通这些值。

于 2012-08-01T20:31:18.033 回答
0

一些猜测,但也许这就是你想要做的:

// Split indexes string to integers
var indexes = strIndexes.Split(',').Select(int.Parse);

// Read file once
var lines = File.ReadLines(myFile);

// Split them (thank you, devundef!)
var splitLines = lines.Select(line => line.Split('|')).ToArray();

// Create dictionary index => column array
var dict = indexes.ToDictionary(
        index => index,
        index => splitLines.Select(splitLine => splitLine[index]).ToArray()
    );
于 2012-08-01T20:42:42.370 回答
0

首先,在查询之外解析您的索引字符串 (strIndex) 以避免多次重复该步骤:

string strIndexes = "7,2,3,9";
int[] indexes = Array.ConvertAll(strIndexes.Split(','), e => int.Parse(e) - 1);

请注意,我将 7 放在首位,因为假设第一个索引是您的关键索引可以简化所需的代码。我还注意到您的索引在字符串中似乎是从 1 开始的,这就是为什么我减去 1 来创建一个从 0 开始的索引数组。然后这会产生Dictionary<string, string[]>您要求的表格:

var selected = (from line in File.ReadLines(myFile)
                let lineArray = line.Split('|')
                select (from index in indexes
                select lineArray[index]))
               .ToDictionary(key => key.First(), value => value.Skip(1).ToArray());

对您的 4 行示例数据运行此操作会产生:

[fr]->[ab, de, hy]
[ds]->[12, f4, 12]
[dq]->[fd, 3d, dd]
[23]->[df, f3, 44]

从此代码:

foreach (var item in selected)
{
    Console.WriteLine("[{0}]->[{1}]", item.Key, string.Join(", ", item.Value));
}
于 2012-08-01T21:02:54.960 回答
0

尽管您要求使用 linq 解决方案,但我认为这可能不是一个好习惯,因为您的文件很大,并且您将为单个任务分配大量内存,甚至会出现 OutOfMemoryException。

您可以只解析文件的每一行并提取每个索引的值:

public Dictionary<int, List<String>> ParseFile(String fileName, int[] indexes)
    var file = File.OpenText(myFile);
    var dict = indexes.ToDictionary(i => i, i => new List<string>());

    while(!file.EndOfStream)
    {
        var line = file.ReadLine().Split('|');
        foreach(var entry in dict)
            entry.Value.Add(line[entry.Key]);
    }
    file.Dispose();
    return dict;
}
于 2012-08-01T21:25:55.177 回答