Select 行来自基于 ID 列表的 CSV
Select rows from CSV based on a list of IDs
我的任务是从包含指定 ID 的 CSV 文件中提取几十万行。所以我有大约 300,000 个 ID 存储在一个字符串列表中,需要提取 CSV 中包含任何这些 ID 的任何行。
目前我正在使用 Linq 语句查看每一行是否包含列表中的任何 ID:
using (StreamReader sr = new StreamReader(csvFile))
{
string inLine = sr.ReadLine();
if(searchStrings.Any(sr.ReadLine().Contains))
{
stremWriter.Write(inLine);
}
}
这种方法可以,但速度很慢,因为 searchStrings 列表中有 300,000 个值,而我需要搜索的 CSV 文件中有几百万行。
有谁知道如何使此搜索更有效以加快速度?
或者提取所需行的替代方法?
谢谢
我以前遇到过类似的问题,我不得不遍历几十万行 .csv 并解析每一行。
我采用了一种线程化方法,尝试同时分批进行读取和解析。
这是大致我是如何做到的;
using System.Collections.Concurrent; using System.Threading;
private static ConcurrentBag<String> items = new ConcurrentBag<String>();
private static List<String> searchStrings;
static void Main(string[] args)
{
using (StreamReader sr = new StreamReader(csvFile))
{
const int buffer_size = 10000;
string[] buffer = new string[buffer_size];
int count = 0;
String line = null;
while ((line = sr.ReadLine()) != null)
{
buffer[count] = line;
count++;
if (count == buffer_size)
{
new Thread(() =>
{
find(buffer);
}).Start();
buffer = new String[buffer_size];
count = 0;
}
}
if (count > 0)
{
find(buffer);
}
//some kind of sync here, can be done with a bool - make sure all the threads have finished executing
foreach (var str in searchStrings)
streamWriter.write(str);
}
}
private static void find(string[] buffer)
{
//do your search algorithm on the array of strings
//add to the concurrentbag if they match
}
我只是快速地将这段代码从我记得以前做过的事情中拼凑起来,所以它可能不完全正确。这样做肯定会加快速度(至少对于非常大的文件)。
想法是始终从硬盘读取,因为字符串解析可能非常昂贵,因此在多核上批处理工作可以显着加快速度。
有了这个,我能够解析(将每行分成大约 50 个项目并解析 key/value 对并从中构建内存中的对象 - 迄今为止最耗时的部分)大约 250k 行刚刚超过 7 秒。
只是把它扔在那里,它与您问题中的任何标签都没有特别相关,但 *nix "grep -f" 功能可以在这里使用。本质上,您将拥有一个包含要匹配的字符串列表的文件(例如,StringsToFind.txt),并且您将拥有您的 csv 输入文件(例如,input.csv),以下命令将输出output.csv
的匹配行
grep -f StringsToFind.txt input.csv > output.csv
有关详细信息,请参阅 grep man page。
我的任务是从包含指定 ID 的 CSV 文件中提取几十万行。所以我有大约 300,000 个 ID 存储在一个字符串列表中,需要提取 CSV 中包含任何这些 ID 的任何行。 目前我正在使用 Linq 语句查看每一行是否包含列表中的任何 ID:
using (StreamReader sr = new StreamReader(csvFile))
{
string inLine = sr.ReadLine();
if(searchStrings.Any(sr.ReadLine().Contains))
{
stremWriter.Write(inLine);
}
}
这种方法可以,但速度很慢,因为 searchStrings 列表中有 300,000 个值,而我需要搜索的 CSV 文件中有几百万行。
有谁知道如何使此搜索更有效以加快速度? 或者提取所需行的替代方法?
谢谢
我以前遇到过类似的问题,我不得不遍历几十万行 .csv 并解析每一行。
我采用了一种线程化方法,尝试同时分批进行读取和解析。 这是大致我是如何做到的;
using System.Collections.Concurrent; using System.Threading;
private static ConcurrentBag<String> items = new ConcurrentBag<String>();
private static List<String> searchStrings;
static void Main(string[] args)
{
using (StreamReader sr = new StreamReader(csvFile))
{
const int buffer_size = 10000;
string[] buffer = new string[buffer_size];
int count = 0;
String line = null;
while ((line = sr.ReadLine()) != null)
{
buffer[count] = line;
count++;
if (count == buffer_size)
{
new Thread(() =>
{
find(buffer);
}).Start();
buffer = new String[buffer_size];
count = 0;
}
}
if (count > 0)
{
find(buffer);
}
//some kind of sync here, can be done with a bool - make sure all the threads have finished executing
foreach (var str in searchStrings)
streamWriter.write(str);
}
}
private static void find(string[] buffer)
{
//do your search algorithm on the array of strings
//add to the concurrentbag if they match
}
我只是快速地将这段代码从我记得以前做过的事情中拼凑起来,所以它可能不完全正确。这样做肯定会加快速度(至少对于非常大的文件)。
想法是始终从硬盘读取,因为字符串解析可能非常昂贵,因此在多核上批处理工作可以显着加快速度。
有了这个,我能够解析(将每行分成大约 50 个项目并解析 key/value 对并从中构建内存中的对象 - 迄今为止最耗时的部分)大约 250k 行刚刚超过 7 秒。
只是把它扔在那里,它与您问题中的任何标签都没有特别相关,但 *nix "grep -f" 功能可以在这里使用。本质上,您将拥有一个包含要匹配的字符串列表的文件(例如,StringsToFind.txt),并且您将拥有您的 csv 输入文件(例如,input.csv),以下命令将输出output.csv
的匹配行grep -f StringsToFind.txt input.csv > output.csv
有关详细信息,请参阅 grep man page。