Читайте CSV, используя LINQ - PullRequest
       11

Читайте CSV, используя LINQ

23 голосов
/ 25 февраля 2011

У меня есть CSV-файл, подобный этому

A, 22, 23, 12
B, 32, 4, 33
C, 34, 3 ,33

Я хочу напечатать сумму и среднее значение каждой строки и пропустить первый столбец.Как это сделать в LINQ используя Lambda

Ответы [ 9 ]

39 голосов
/ 25 февраля 2011
var stuff = from l in File.ReadAllLines(filename)
            let x = l.Split(new [] {',', ' '}, StringSplitOptions.RemoveEmptyEntries)
                     .Skip(1)
                     .Select(s => int.Parse(s))
            select new
            {
                Sum = x.Sum(),
                Average = x.Average()
            };

Если вы читаете большие файлы и использование памяти вызывает беспокойство, то с помощью .NET 4 будет работать лучше:

var stuff = from l in File.ReadLines(filename)
            let x = l.Split(new [] {',', ' '}, StringSplitOptions.RemoveEmptyEntries)
                     .Skip(1)
                     .Select(s => int.Parse(s))
            select new
            {
                Sum = x.Sum(),
                Average = x.Average()
            };

В обоих случаях переменная stuff содержитперечислимое, которое на самом деле не будет выполняться, пока вы не начнете читать из него (например, внутри цикла foreach).

9 голосов
/ 25 февраля 2011
        string csvFile = @"myfile.csv";
        string[] lines = File.ReadAllLines(csvFile);

        var values = lines.Select(l => new { FirstColumn = l.Split(',').First(), Values = l.Split(',').Skip(1).Select(v => int.Parse(v)) });
        foreach (var value in values)
        {
            Console.WriteLine(string.Format("Column '{0}', Sum: {1}, Average {2}", value.FirstColumn, value.Values.Sum(), value.Values.Average()));
        }
6 голосов
/ 25 февраля 2011

Попробуйте использовать эту старую, но все же хорошую библиотеку: FileHelpers Library

Это очень удобно:

char delimiter = ',';
var dt = FileHelpers.CsvEngine.CsvToDataTable(fileName,delimiter);

тогда просто сделайте:

var rowStats = dt.AsEnumerable()
                 .Select(x => x.ItemArray.Select(y => Convert.ToInt32(y)))
                 .Select(x => new { avg = x.Average(), sum = x.Sum() });

foreach (var rowStat in rowStats)
{
    Console.WriteLine("Sum: {0}, Avg: {1}", rowStat.sum, rowStat.avg);
}
5 голосов
/ 25 февраля 2011
string[] csvlines = File.ReadAllLines(@txtCSVFile.Text);

var query = from csvline in csvlines
  let data = csvline.Split(',')
  select new
  {
   ID = data[0],
   FirstNumber = data[1],
   SecondNumber = data[2],
   ThirdNumber = data[3]
  };
2 голосов
/ 21 ноября 2012

Я только что обнаружил библиотеку LinqToCsv, она выполняет все операции разбора, а затем вы можете запрашивать объекты, такие как коллекции, и поддерживает отложенное чтение:

http://www.codeproject.com/Articles/25133/LINQ-to-CSV-library

0 голосов
/ 19 июня 2019

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

Я даю вам лучшее универсальное решение с использованием Regex и простое в использовании:

var stuff = File.ReadAllLines(csvFilePath)
    .Skip(1) // For header
    .Select(s => Regex.Match(s, @"^(.*?),(.*?),(.*?),(.*?),(.*?)$"))
    .Select(data => new 
    {
        Foo = data.Groups[1].Value,
        Bar = data.Groups[2].Value,
        One = data.Groups[3].Value,
        Two = data.Groups[4].Value,
    });

А подробности можно найти здесь https://stackoverflow.com/a/18147076/196526

0 голосов
/ 25 февраля 2011
using System.IO

// turn file into IEnumerable (streaming works better for larger files)
IEnumerable<Tuple<int, int, int>> GetTypedEnumerator(string FilePath){
  var File = File.OpenText(FilePath);
  while(!File.EndOfStream) 
      yield return new Tuple<int, int, int>(
          Int.Parse(File[1]), 
          Int.Parse(File[2], 
          Int.Parse(File[3])
      );
   File.Close();
}

// this lines would return the sum and avg for each line
var tot = GetTypeEnumerator(@"C:\file.csv").Select(l=>l.Item1 + l.Item2 + l.Item3);
var avg = GetTypeEnumerator(@"C:\file.csv").Select(l=> (l.Item1 + l.Item2 + l.Item3) / 3);

Потоковый aporoach позволит вам обрабатывать файлы laregr, потому что вам не нужно сначала загружать их в память. Здесь нет VS, синтаксис не проверен, может не компилироваться как есть.

С уважением GJ

Блин, ответов уже много, надо набирать быстрее!

0 голосов
/ 25 февраля 2011

Примерно так:

var csv = @"A, 22, 23, 12
B, 32, 4, 33
C, 34, 3 ,33";

var lines =
    csv.Split('\n').Select(x => x.Split(',').Skip(1).Select(n => int.Parse(n))).Select(x => new {Sum = x.Sum(), Average = x.Average()});
foreach (var line in lines)
{
    Console.WriteLine("Sum: " + line.Sum);
    Console.WriteLine("Average: " + line.Average);
}

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

0 голосов
/ 25 февраля 2011

Привет вы ищете что-то вроде этого

  var rows = new List<string> {"A, 22, 23, 12", "B, 32, 4, 33", "C, 34, 3 ,33"};
     foreach (var row in rows) {
            var sum = row.Split(',').Skip(1).Sum(x => Convert.ToInt32(x));
            var avg = row.Split(',').Skip(1).Average(x => Convert.ToInt32(x));
     }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...