Как объединить несколько List
Есть 1000 файлов с email-ами. Нужны посчитать email;количество повторений суммарно во всех файлах. Так как строк очень много, не могу все держать в памяти. Приходится держать глобальный список var all = new List<DB>(), в котором я и буду хранить данные после обработки каждого файла.
public class DB
{
public string Email { get; set; }
public int Total { get; set; }
}
Вопрос. Как объединить две коллекции List<DB>, чтобы поля Email и Total "суммировались"?
Ответы (1 шт):
Стандартная же задача.
Вот так проходим по всем файлам. Файл целиком в память не грузим, берём по строке.
var dict = new Dictionary<string, int>();
foreach (var file in Directory.EnumerateFiles(path))
{
foreach (var line in File.ReadLines(file))
{
if (dict.ContainsKey(line))
dict[line]++;
else
dict.Add(line, 1);
}
}
Подразумевается, что каждый email находится на отдельной строке. В реальном коде добавить Trim() и т. п.
Полагаю, есть смысл при создании словаря задать ему большую ёмкость изначально. И нужно задать правильный компаратор.
var dict = new Dictionary<string, int>(1_000_000, StringComparer.OrdinalIgnoreCase);
Ответ уже принят, а я надеялся на развитие дискуссии. Ведь если из 500 млн. строк большинство являются уникальными и е-мейлы длинные, то суммарно может понадобиться несколько десятков гигабайт оперативки.
Соответственно я хотел предложить следующий код
foreach (var file in Directory.EnumerateFiles(path))
{
foreach (var line in File.ReadLines(file))
{
if (dict.ContainsKey(line))
dict[line]++;
else
dict.Add(line, 0);
}
AddToStore(dict);
dict.Clear();
}
Здесь данные из словаря сбрасываются в некое внешнее хранилище (можно sqlite прикрутить) после каждого файла. После чего словарь очищается.
Другой вариант, сбрасывать данные в случае достижения определённого размера словаря. Этот вариант лучше тем, что если дубликатов много, то вызов AddToStore произойдёт меньшее количество раз.
foreach (var file in Directory.EnumerateFiles(path))
{
foreach (var line in File.ReadLines(file))
{
if (dict.ContainsKey(line))
{
dict[line]++;
}
else
{
if (dict.Count >= 1_000_000)
{
AddToStore(dict);
dict.Clear();
}
dict.Add(line, 0);
}
}
}
Сигнатура метода:
void AddToStore(IDictionary<string, int> dict)
{
// тут добавляем данные из словаря в некое хранилище
}