我有一个包含以下数据的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
小计,以便我可以将其与请求的金额进行比较,以便计算可用的最佳金额。即" 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; }
}
}
答案 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;中加入了一轮。对于率。