从 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),将 Rate
和 Available
转换为合适的数字类型(将 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' 的比率。
我有一个包含如下数据的 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),将 Rate
和 Available
转换为合适的数字类型(将 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' 的比率。