好的,所以标题不是最好的。但这是我的问题:
我做了一个小程序,当一个外部程序发生某些事件时,会向.txt文档写一些名字和一个整数。
问题在于文档中的名称可以显示在几行中,所以我想为每个特定的人提供整数,以便我得到他/她的总分,然后对其进行排序。
例如:
原始行:
Aaaa Aaa 5
Bbbb Bbb 7
Cccc Ccc 2
Aaaa Aaa 4
Cccc Ccc 4
Bbbb Bbb 1
Dddd Ddd 1
我想要的输出:
1. Aaaa Aaa 9
2. Bbbb Bbb 8
3. Cccc Ccc 6
4. Dddd Ddd 1
有没有办法在C#中这样做? 我试图读取文件中的每一行并搜索一个人的名字。但这并没有真正帮助,我不知道如何解决这个问题。 有什么建议吗?
答案 0 :(得分:3)
显然,文本在某种程度上是用来总结数字的关键,那么为什么不先使用Dictionary<string, int>
进行总结并稍后再写呢?
示例:
Dictionary<string, int> sums = new Dictionary<string, int>();
...
if (sums.ContainsKey(theNewString))
sums[theNewString] += theNewNumber;
else
sums[theNewString] = theNewNumber;
当你知道你已经完成时,写下这个文件。您还可以在每次更新字典后重新编写该文件,但请记住,如果您不清除它,字典将会增长和增长。
另外:如果程序重新启动,这将不起作用,除非您每次程序启动时都创建一个新文件。否则,当程序开始继续总结时,你必须将现有文件读入字典。
答案 1 :(得分:2)
使用键作为名称创建字典。作为字典中每个项目的值,使用整数并将其添加到已存在的键(的值)(或不)。
答案 2 :(得分:2)
lines.GroupBy(line => string.Join(" ", line.Split().Take(2)))
.Select((g, index) =>
string.Format("{0}. {1} {2}",
index,
g.Key,
g.Sum(line => int.Parse(line.Split().Last()))));
答案 3 :(得分:2)
此Linq查询返回所需的结果IEnumerable<string>
:
IEnumerable<string> lineGroups = File.ReadLines(path)
.Select((l, i) => new { Line = l, Parts = l.Split() })
.Select(x => new
{
Number = x.Parts.ElementAtOrDefault(2).TryGetInt() ?? 1,
Col1 = x.Parts.ElementAtOrDefault(0),
Col2 = x.Parts.ElementAtOrDefault(1),
x.Line,
x.Parts
})
.GroupBy(x =>new { x.Col1, x.Col2 })
.Select((g, groupIndex) =>
string.Format("{0}. {1} {2} {3}",
groupIndex + 1, g.Key.Col1, g.Key.Col2, g.Sum(x => x.Number)));
输出:
foreach (var grp in lineGroups)
Console.WriteLine(grp);
这是输出:
1. Aaaa Aaa 9
2. Bbbb Bbb 8
3. Cccc Ccc 2 // different than your desired ouput but seems to be correct
4. Dddd Ddd 1
这些是我在Linq查询中使用的扩展方法,试图将string
解析为常见值类型,如int
(如上所述)。如果它不可解析,则返回可空类型:
public static class NumericExtensions
{
public static bool IsBetween(this int value, int fromInclusive, int toInclusive)
{
return value >= fromInclusive && value <= toInclusive;
}
public static Decimal? TryGetDecimal(this string item)
{
Decimal d;
bool success = Decimal.TryParse(item, out d);
return success ? (Decimal?)d : (Decimal?)null;
}
public static int? TryGetInt(this string item)
{
int i;
bool success = int.TryParse(item, out i);
return success ? (int?)i : (int?)null;
}
public static bool TryGetBool(this string item)
{
bool b = false;
Boolean.TryParse(item, out b);
return b; ;
}
public static Version TryGetVersion(this string item)
{
Version v;
bool success = Version.TryParse(item, out v);
return v;
}
}
答案 4 :(得分:1)
var results = File.ReadAllLines("filename.txt")
.Select(x => x.Split())
.GroupBy(y => new { y1 = y[0], y2 = y[1] })
.Select(g => new { g.Key.y1, g.Key.y2, Sum = g.Sum(v => int.Parse(v[2])) })
.OrderByDescending(p => p.Sum)
.Select(m => m.y1 + " " + m.y2 + " " + m.Sum).ToList();
答案 5 :(得分:1)
类似的东西(不那么优雅,但不依赖于空格的数量)
var lines = File.ReadAllLines(@"<pathToFile>");
var result = lines
.Select(m => m.Split(' '))
.Select(x => new {
text = string.Join(" ", x.Where(z => z != x.Last())),
val = Convert.ToInt32(x.Last())
})
.GroupBy(x => x.text)
.Select(g => new {
text =g.Key,
sum = g.Sum(z => z.val)
}).ToList();
答案 6 :(得分:1)
使用LINQ和正则表达式的另一种解决方案(用于验证行格式并从中获取名称和值):
Regex regex = new Regex(@"^(?<name>.*)\s(?<value>\d+)$");
var query = from line in File.ReadLines(file_name)
let match = regex.Match(line)
where match.Success
select new {
Name = match.Groups["name"].Value,
Value = match.Groups["value"].Value
} into item
group item by item.Name into g
orderby g.Key
select new {
Name = g.Key,
Total = g.Sum(x => Int32.Parse(x.Value))
};
此处未验证值溢出。如果某些值可能大于Int32.MaxValue,则将总和计算更改为
g.Sum(x => { int value; return Int32.TryParse(x.Value, out value) ? value : 0; })