我怎么读几行到同一行?

时间:2013-06-13 10:16:59

标签: c#

好的,所以标题不是最好的。但这是我的问题:

我做了一个小程序,当一个外部程序发生某些事件时,会向.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#中这样做? 我试图读取文件中的每一行并搜索一个人的名字。但这并没有真正帮助,我不知道如何解决这个问题。 有什么建议吗?

7 个答案:

答案 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; })