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

Read from CSV then perform various basic calculations

我有一个包含如下数据的 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,以便我可以将此与请求的金额进行比较,以便计算出可用的最佳费率。 IE。 “0.7 可用 1200,0.8 可用 960”等。我有一些注释掉的代码:

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

这失败了:
错误 CS1061:类型 'loanCalculator.Lender' 不包含 'amountAvailableInt' 的定义,并且找不到类型 'loanCalculator.Lender' 的扩展方法 'amountAvailableInt'。您是否缺少程序集参考? (CS1061) (贷款计算器)

然后我会将这些小计与输入的金额进行比较,return 最低比率,运行 使用输入的金额和比率进行一些计算。

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

我的完整代码如下。

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; }
    }
}

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

您的第一个问题是 "Available" 和 "Rate" 都列为字符串 - 将它们更改为数字类型,您会发现它变得更容易。希望您的 CSV 助手会为您转换内容;

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

接下来,我将介绍如何使用 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 获取一个项目并将其转换为另一个项目。在这个蛋糕中,我们采用上面的分组对象和 return 一个带有 Rate 属性 的新对象(看看它是如何从上一步中去除 Key 的?)和一个Sum属性; g.Sum(x=>x.Available) 读作 "sum the group by summing the Available property of every item x"

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

Where 函数将列表过滤为特定项目。在这种情况下,我们保留 Sum > 0 的任何地方;这是您的要求,只关心可用的价格

    .OrderBy(g => g.Rate)

OrderBy 函数 return 是项目的排序序列。在这种情况下,我们按汇率排序,因此列表顶部的汇率最低(最佳)。

    .First();

First 函数 return 是列表中的第一项。 (想想 SQL 中的 select top(1) *)。

总而言之,我们;

  • 按比率分组
  • 总计可用优惠
  • 删除 none 可用的费率
  • 按最佳-最差顺序排列
  • 从排序列表的顶部取最好的

EDIT 合并了一个 'round to 2dp' 的比率。