我需要一个用C#编写的程序
第一列包含无线电标识(1-2-3) 第二栏是关于歌曲播放时间的分钟 第三列是以秒为单位的歌曲播放时间 最后两个是表演者:歌曲
所以文件看起来像这样:
1 5 3深紫色:态度不好
2 3 36 Eric Clapton:Terraplane Blues
3 2 46 Eric Clapton:Crazy Country Hop
3 3 25欧米茄:Ablakok
2 4 23 Eric Clapton:如果你能抓住我
1 3 27 Eric Clapton:Willie和The Hand Jive
3 4 33欧米茄:一个szamuzott
................. 更多670行。
到目前为止我得到了这个: using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace radiplaytime
{
public struct Adat
{
public int rad;
public int min;
public int sec;
public Adat(string a, string b, string c)
{
rad = Convert.ToInt32(a);
min = Convert.ToInt32(b);
sec = Convert.ToInt32(c);
}
}
class Program
{
static void Main(string[] args)
{
String[] lines = File.ReadAllLines(@"...\zenek.txt");
List<Adat> adatlista = (from adat in lines
//var adatlista = from adat in lines
select new Adat(adat.Split(' ')[0],
adat.Split(' ')[1],
adat.Split(' ')[2])).ToList<Adat>();
var timesum = (from adat in adatlista
group adat by adat.rad into ertekek
select new
{
rad = ertekek.Key,
hour = (ertekek.Sum(adat => adat.min) +
ertekek.Sum(adat => adat.sec) / 60) / 60,
min = (ertekek.Sum(adat => adat.min) +
ertekek.Sum(adat => adat.sec) / 60) % 60,
sec = ertekek.Sum(adat => adat.sec) % 60,
}).ToArray();
for (int i = 0; i < timesum.Length; i++)
{
Console.WriteLine("{0}. radio: {1}:{2}:{3} playtime",
timesum[i].rad,
timesum[i].hour,
timesum[i].min,
timesum[i].sec);
}
Console.ReadKey();
}
}
}
答案 0 :(得分:1)
您可以定义自定义类来存储每行的值。您将需要使用正则表达式来拆分每一行并填充您的自定义类。然后,您可以使用linq获取所需的信息。
public class Plays
{
public int RadioID { get; set; }
public int PlayTimeMinutes { get; set; }
public int PlayTimeSeconds { get; set; }
public string Performer { get; set; }
public string Song { get; set; }
}
然后,您阅读文件并填充自定义播放:
String[] lines = File.ReadAllLines(@"songs.txt");
List<Plays> plays = new List<Plays>();
foreach (string line in lines)
{
var matches = Regex.Match(line, @"^(\d+)\s(\d+)\s(\d+)\s(.+)\:(.+)$"); //this will split your line into groups
if (matches.Success)
{
Plays play = new Plays();
play.RadioID = int.Parse(matches.Groups[1].Value);
play.PlayTimeMinutes = int.Parse(matches.Groups[2].Value);
play.PlayTimeSeconds = int.Parse(matches.Groups[3].Value);
play.Performer = matches.Groups[4].Value;
play.Song = matches.Groups[5].Value;
plays.Add(play);
}
}
现在你已经有了歌曲列表,你可以使用linq来获得你需要的东西:
//Get Total Eric Clapton songs played - assuming distinct songs
var ericClaptonSongsPlayed = plays.Where(x => x.Performer == "Eric Clapton").GroupBy(y => y.Song).Count();
//get eric clapton songs played on all radio stations
var radioStations = plays.Select(x => x.RadioID).Distinct();
var commonEricClaptonSong = plays.Where(x => x.Performer == "Eric Clapton").GroupBy(y => y.Song).Where(z => z.Count() == radioStations.Count());
等
答案 1 :(得分:0)
字符串拆分仅在文本真正简单并且不必处理固定长度字段时才有效。它还会生成许多临时字符串,这会导致程序占用RAM中原始数量的许多倍,并且由于常量分配和垃圾回收而损害性能。
Riv的回答显示了如何使用正则表达式来解析此文件。它可以通过以下几种方式进行改进:
var pattern=@"^(\d+)\s(\d+)\s(\d+)\s(.+)\:(.+)$";
var regex=new Regex(pattern);
var plays = from line in File.ReadLines(filePath)
let matches=regex.Match(line)
select new Plays {
RadioID = int.Parse(matches.Groups[1].Value),
PlayTimeMinutes = int.Parse(matches.Groups[2].Value),
PlayTimeSeconds = int.Parse(matches.Groups[3].Value),
Performer = matches.Groups[4].Value,
Song = matches.Groups[5].Value
};
ReadLines
返回IEnumerable<string>
,而不是在缓冲区中返回所有行。这意味着解析可以立即开始例如:
var durations = plays.GroupBy(p=>p.RadioID)
.Select(grp=>new { RadioID=grp.Key,
Hours = grp.Sum(p=>p.PlayTimeMinutes + p.PlayTimeSecons/60)/60,)
Mins = grp.Sum(p=>p.PlayTimeMinutes + p.PlayTimeSecons/60)%60,)
Secss = grp.Sum(p=> p.PlayTimeSecons)%60)
});
进一步改善可能是给小组起名字:
var pattern=@"^(?<station>\d+)\s(?<min>\d+)\s(?<sec>\d+)\s(?<performer>.+)\:(?<song>.+)$";
...
select new Plays {
RadioID = int.Parse(matches.Groups["station"].Value),
PlayTimeMinutes = int.Parse(matches.Groups["min"].Value),
...
};
你也可以摆脱Plays
类并使用一个稍微复杂的LINQ查询:
var durations = from line in File.ReadLines(filePath)
let matches=regex.Match(line)
let play= new {
RadioID = int.Parse(matches.Groups["station"].Value),
Minutes = int.Parse(matches.Groups["min"].Value),
Seconds = int.Parse(matches.Groups["sec"].Value)
}
group play by play.RadioID into grp
select new { RadioID = grp.Key,
Hours = grp.Sum(p=>p.Minutes + p.Seconds/60)/60,)
Mins = grp.Sum(p=>p.Minutes + p.Seconds/60)%60,)
Secs = grp.Sum(p=> p.Seconds)%60)
};
在这种情况下,不会为Performer
和Song
生成任何字符串。这是正则表达式的另一个好处。匹配和组只是原始字符串的索引。在读取.Value
之前不会生成任何字符串。这会使本案中使用的RAM减少约75%。
获得结果后,您可以迭代它们:
foreach (var duration in durations)
{
Console.WriteLine("{0}. radio: {1}:{2}:{3} playtime",
duration.RadioID,
duration.Hours,
duration.Mins,
duration.Secs);
}