从CSV读取然后执行各种基本计算

时间:2015-12-02 11:05:04

标签: c# csv subtotal

我有一个包含以下数据的CSV文件:

Lender,Rate,Available
Bob,0.075,640
Jane,0.069,480
Fred,0.071,520
Mary,0.104,170
John,0.081,320
Dave,0.074,140
Angela,0.071,60

我需要提取这些数据,并构建一个程序,该程序将获取值输入并计算Rate的最低(最佳)Available。例如。如果我运行它进入1000它将以0.7(舍入率为2dp)的速率向我提供,因为在该速率下至少有1000个可用,并且该速率是可用的最低速率。 到目前为止,我已经能够从CSV文件中读取(使用CsvHelper),将RateAvailable转换为合适的数字类型(将Rate减少到2个小数位),然后排序依据Rate。输出是:

Jane, 0.07, 480
Fred, 0.07, 520
Angela, 0.07, 60
Dave, 0.07, 140
Bob, 0.08, 640
John, 0.08, 320
Mary, 0.1, 170

我现在尝试将Available金额按Rate小计,以便我可以将其与请求的金额进行比较,以便计算可用的最佳金额。即" 1200可用0.7,960可用0.8"我有一些注释掉的代码:

var grouped = lendersFromCsv.GroupBy(x=>x.Rate)
                            .Select(g => new {Rate = g.Key, 
                            Sum = g.Sum(x => x.amountAvailableInt)});

这失败了:
 错误CS1061:输入' loanCalculator.Lender'不包含' amountAvailableInt'的定义并且没有任何延期方法' amountAvailableInt'类型' loanCalculator.Lender'可以找到。你错过了装配参考吗? (CS1061)(loanCalculator)

然后我将这些小计与输入的数量进行比较,返回最低费率并使用输入的金额和费率进行一些计算。

我想我有点迷失(作为C#的完全初学者)关于从market.csv中提取数据然后使用该数据的最佳方法。我看到很多将所有内容存储到列表中的示例,而我目前正在做的事情并不是真的感觉不错。 所以,两个问题线程......假设我继续这是徒劳的,我该如何进行小计?其次,我需要改变方法吗?

我的完整代码如下。

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;

using CsvHelper;

namespace loanCalculator
{
    class Program
    {
        public static void Main (string[] args)
        {
            using (TextReader reader = File.OpenText(@"market.csv"))
            {
                var csv = new CsvReader(reader);

                var lendersFromCsv = csv.GetRecords<Lender>();

                foreach (var lender in lendersFromCsv.OrderBy(x => x.Rate)) 
                {
                    var name = lender.Name;
                    double rateAsDbl = Math.Round(double.Parse(lender.Rate),2);
                    int amountAvailableInt = int.Parse (lender.Available);

                    Console.WriteLine("{0}, {1}, {2}",
                        name,
                        rateAsDbl,
                        amountAvailableInt);

//                  var grouped = lendersFromCsv.GroupBy(x=>x.Rate)
//                      .Select(g => new {Rate = g.Key, 
//                          Sum = g.Sum(x => x.amountAvailableInt)});
                }
            }
            Console.ReadKey ();
        }
    }

    public class Lender
    {
        public String Name { get; set; }
        public String Rate { get; set; }
        public String Available { get; set; }
    }
}

1 个答案:

答案 0 :(得分:2)

linq表达式看起来是正确的方法,但作为初学者,它看起来有点不自然(你听起来像C#初学者,而不是初学程序员)

你的第一个问题是&#34;可用&#34;和&#34;评价&#34;都被列为String - 将它们更改为数字类型,您会发现它变得更容易。希望您的CSV助手可以为您转换内容;

public class Lender
{
    public String Name { get; set; }
    public decimal Rate { get; set; }
    public decimal Available { get; set; }
}

接下来,这里&#39;我如何使用linq表达式来处理它。方法是将方法链接在一起,将初始列表转换为各种其他列表。在每一点上,尝试应用单个操作 - 过滤掉项目,执行总和,排序等。这就是我想出的内容;

// test data
var lenders = new Lender[] { 
    new Lender { Name="Alice", Rate=0.29887m, Available=5 },
    new Lender { Name="Bob", Rate=0.29555m, Available=10 },
    new Lender { Name="Charlie", Rate=0.5000m, Available=20 },
};

var bestRate = lenders
    .GroupBy(x => decimal.Round(x.Rate, 2, MidpointRounding.AwayFromZero))
    .Select(g => new { Rate = g.Key, Sum = g.Sum(x => x.Available) })
    .Where(g => g.Sum > 0)
    .OrderBy(g => g.Rate)
    .First();


Console.WriteLine("{0}, {1}", bestRate.Rate, bestRate.Sum);

写出来;

0.3, 15

这表明有15个可用的速率在0.295-0.305之间。

逐行分开;

var bestRate = lenders
    .GroupBy(x => decimal.Round(x.Rate, 2, MidpointRounding.AwayFromZero))

取出贷方并按汇率将它们组合在一起,四舍五入为2dp。所以你得到一系列看起来像的对象;

{ 
    Key: 0.3, Value: [ 
        { Name="Alice", Rate=0.29887, Available=5 }, 
        { Name="Bob", Rate=0.29555, Available=10 }
    ]
},
{ 
    Key: 0.5, Value: [ 
        { Name="Charlie", Rate=0.50000, Available=20 }, 
    ]
},

下一步;

.Select(g => new { Rate = g.Key, Sum = g.Sum(x => x.Available) })

Select获取一个项目并将其转换为另一个项目。在这个蛋糕中,我们采用上面的分组对象并返回一个具有Rate属性的新对象(请参阅它如何去除上一步中的Key?)和Sum属性; g.Sum(x=>x.Available)读作&#34;通过将每个项目的可用属性相加来对该组求和x&#34;

    .Where(g => g.Sum > 0)

Where功能会将列表过滤到特定项目。在这种情况下,我们保留在Sum&gt;的任何地方。 0;这是您要求只关心可用的费率

    .OrderBy(g => g.Rate)

OrderBy函数返回已排序的项目序列。在这种情况下,我们按费率排序,因此列表的顶部具有最低(最佳)费率。

    .First();

First函数返回列表中的第一项。 (在SQL中考虑select top(1) *)。

总而言之,我们;

  • 按费率分组
  • 总计可用的优惠总数
  • 删除无法使用的费率
  • 按最佳最差订购
  • 从排序列表的顶部采取最好的

编辑在2dp&#39;中加入了一轮。对于率。