Разделить несколько CSV-файлов по значению из одного CSV-файла с помощью C # - PullRequest
0 голосов
/ 30 декабря 2018

Мне нужно открыть файл CSV.Затем мне нужно отфильтровать все данные и сгенерировать вывод для каждого их значения.

◘ Пример

• Входной файл = "полный список.csv"

NAME        CITY
Mark        Venezia
John        New York
Lisa        San Miguel
Emily       New York
Amelia      New York
Nicolas     Venezia
Bill        San Miguel
Steve       Venezia

Выводбудет =

• file1 = "full list_Venezia.csv"

NAME        CITY
Mark        Venezia
Nicolas     Venezia
Steve       Venezia

• file2 = "full list_New York.csv"

NAME        CITY
John        New York
Emily       New York
Amelia      New York

• file3 = "full list_San Miguel "

NAME        CITY
Lisa        San Miguel
Bill        San Miguel

Я использую c # с ConsoleApplication в Visual Studio и начал читать входной файл следующим способом:

string inputFile = "full list.csv";
string outputFile;
string line;
string titles = File.ReadLines(inputFile).First();
System.IO.StreamReader file = new System.IO.StreamReader(inputFile);
while ((line = file.ReadLine()) != null)
{
}
file.Close();

System.IO.StreamWriter fileOut = new System.IO.StreamWriter(outputFile);
foreach (DatiOutput objOut in listOutput)
{
}
fileOut.Close();

Существует ли алгоритм, который позволяетмне отфильтровать нужные мне данные?

Ответы [ 4 ]

0 голосов
/ 30 декабря 2018

Это не-LINQy подход с использованием словаря для сохранения ссылки на каждый выходной файл на основе названия города в качестве ключа (хотя в LINQ нет ничего плохого!):

string[] values;
string header;
string line, city, outputFileName;
string inputFile = "full list.csv";
Dictionary<string, System.IO.StreamWriter> outputFiles = new Dictionary<string, System.IO.StreamWriter>();
using (System.IO.StreamReader file = new System.IO.StreamReader(inputFile))
{
    header = file.ReadLine();
    while ((line = file.ReadLine()) != null)
    {
        values = line.Split(",".ToCharArray());
        city = values[1];
        if (!outputFiles.ContainsKey(city))
        {
            outputFileName = "full list_" + city + ".csv";
            outputFiles.Add(city, new System.IO.StreamWriter(outputFileName));
            outputFiles[city].WriteLine(header);
        }
        outputFiles[city].WriteLine(line);
    }
}   
foreach(System.IO.StreamWriter outputFile in outputFiles.Values)
{
    outputFile.Close();
}
0 голосов
/ 30 декабря 2018
foreach (var g in File.ReadAllLines("full list.csv")
    .Skip(1)
    .Select(l => new {
        Name = l.Substring(0, l.IndexOf(',')),
        City = l.Substring(l.IndexOf(',') + 1) })
    .GroupBy(l => l.City))
{
    File.WriteAllLines($"full list_{g.Key}.csv", new[] { "NAME,CITY" }
        .Concat(g.Select(l => $"{l.Name},{l.City}")));
}

Ключевая часть, в которой отсутствовал ваш пример, была GroupBy - это позволяет группировать данные, которые вы прочитали, в группы на основе определенных критериев (в нашем случае - города).

Группироватьмощное расширение LINQ , позволяющее фильтровать данные.Приведенный выше пример считывает все данные, пропускает заголовок и использует select для преобразования каждой строки в экземпляр анонимного типа , в котором содержатся имя и город.GroupBy затем используется для группировки этих экземпляров по городам.Затем для каждой группы данные записываются в новый файл.

0 голосов
/ 30 декабря 2018

Я бы взял ответ @TVOHMs в несколько более четком направлении, сохранив один и тот же стиль кода для всего решения.

File.ReadAllLines("full list.csv")         // Read the input file
    .Skip(1)                               // Skip the header row
    .Select(row => row.Split(','))         // Split each row to array of city and name
    .GroupBy(row => row[1], row => row[0]) // Group by cities, selecting names
    .ToList()                              // To list, so .ForEach is possible
    .ForEach(group => File.WriteAllLines($"full list_{group.Key}.csv", group)); // Create file for each group and write the names
0 голосов
/ 30 декабря 2018

Вы написали большинство хороших частей сами, и теперь вам нужно заполнить пробелы.Разбивка шагов

  • Считывание CSV в коллекцию
  • Групповое собрание по городу
  • Запись каждой группы в отдельный файл

Первым шагом, конечно, является чтение входного файла

var listOutput = new List<DatiOutput>();
while ((line = file.ReadLine()) != null)
{
    var data = line.Split(new []{";"},StringSplitOptions.RemoveEmptyEntries);
    if(!data[0].Trim().Equals("NAME"))
        listOutput.Add(new DatiOutput{ Name = data[0].Trim(), City = data[1].Trim()});
}

Я предположил, что ваш DatiOutput выглядит следующим образом, поскольку он не был задан.

public class DatiOutput 
{
public string City{get;set;}
public string Name{get;set;}
}

Тогда следующим шагом будетГруппировать коллекции по городам, а затем записывать их в файл.Вы можете использовать LINQ для группировки коллекции по городам.

listOutput.GroupBy(c=>c.City)

Получив результат, вы теперь можете создать имя файла с соответствующим названием города и добавить в него данные.

foreach (var objOut in listOutput.GroupBy(c=>c.City))
{
    var filePath = $"{Path.Combine(Path.GetDirectoryName(inputFile),Path.GetFileNameWithoutExtension(inputFile))}_{objOut.First().City}.csv";

    using(System.IO.StreamWriter fileOut = new System.IO.StreamWriter(File.Open(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite)))
    {
        fileOut.WriteLine($"NAME;CITY");
        foreach(var items in objOut)
        {
            fileOut.WriteLine($"{items.Name};{items.City}");
        }
    }
}

Вы бы получили желаемый результат

...