我有一个很长的Log.txt文件,其中包含很多看起来像这样的数据:
001 000 2.59 2.4595 2.4573 2.62
001 001 1.56 1.52 1.51 1.56
001 002 0.67 0.66 0.66 0.67
001 003 0.5 0.4949 0.49 0.5
001 004 0.96 0.9601 0.96 0.9601
001 005 0.5291 0.5001 0.5 0.54
002 000 2.4537 2.4422 2.43 2.4537
002 003 0.5 0.51 0.4945 0.515
002 005 0.5 0.4801 0.4801 0.5
003 000 2.43 2.3399 2.3399 2.43
003 003 0.5101 0.5087 0.5005 0.5289
003 004 1 0.998 0.98 1
003 005 0.49 0.4802 0.4362 0.49
通过第二列将数据分离到列表中的最简单,最专业的方法是什么。 例如: 清单1
001 000 2.59 2.4595 2.4573 2.62
002 000 2.4537 2.4422 2.43 2.4537
003 000 2.43 2.3399 2.3399 2.43
并列出2
001 001 1.56 1.52 1.51 1.56
并列出3
001 002 0.67 0.66 0.66 0.67
以此类推。
我没有经验,所以我可能要做的是:
if (line2.Contains(i.ToString("D3")))
添加... 请告诉我是否有更好的方法。
仅供参考,作为成品,我想遍历每一行,删除所有重复项,然后将所有这些数字添加到5个数组(5个不同的数组001至005)中,并对重复项进行计数。
答案 0 :(得分:2)
我发现创建记录类型以将行导入通常是最简单的。我不知道您的实际专栏是什么,因此请弄乱它,直到您对自己更有意义为止:
public class LogEntry
{
public string GroupIndex;
public string GroupKey;
public float Value1;
public float Value2;
public float Value3;
public float Value4;
}
现在将日志文件作为IEnumerable<LogEntry>
加载,您可以使用LINQ来为您完成工作:
public static IEnumerable<LogEntry> OpenLog(string filename)
{
using (var reader = new StreamReader(filename))
{
string line = null;
while ((line = reader.ReadLine()) != null)
{
string[] parts = line.Split(' ');
if (parts.Length != 6)
continue;
float f1, f2, f3, f4;
if (!float.TryParse(parts[2], out f1) || !float.TryParse(parts[3], out f2) || !float.TryParse(parts[4], out f3) || !float.TryParse(parts[5], out f4)
continue;
yield return new LogEntry
{
GroupIndex = parts[0],
GroupKey = parts[1],
Value1 = f1,
Value2 = f2,
Value3 = f3,
Value4 = f4,
}
}
}
}
现在,我们已经可以访问文件数据作为LINQ可以检查的具体记录,分组将解决您的大部分问题。首先,让我们对数据的第二列(在上面的记录中称为GroupKey
)进行分组:
var groupedEntries =
(
from entry in OpenLog(logfilename)
// first group by the group key - second column in data
group entry by entry.GroupKey into grp
select new
{
Group = grp.Key,
Data = grp.ToArray(),
}
).ToArray();
您现在可以获取结果数组并分别处理它们以获取重复项。为了便于讨论,我假设您正在寻找所有4个值字段中的重复值。其他比较也是如此...
var deduplicated =
(
from grp in groupedEntries
let dedup =
(
from ent in grp
group ent.GroupIndex by new { ent.Value1, ent.Value2, ent.Value3, ent.Value4 } into ddgrp
let first = grp.First()
select new
{
first.GroupIndex, first.GroupKey,
first.Value1, first.Value2, first.Value3, first.Value4,
Count = ddgrp.Count(),
}
).ToArray()
select new
{
grp.Key,
Data = dedup,
}
).ToArray();
现在您有了这样的记录数组(在JSON中):
[
{
"Group": "000",
"Data": [
{
"GroupIndex": "001",
"GroupKey": "000",
"Value1": 2.59,
"Value2": 2.4595,
"Value3": 2.4573,
"Value4": 2.62,
"Count": 1
},
{
"GroupIndex": "001",
"GroupKey": "001",
"Value1": 2.4537,
"Value2": 2.4422,
"Value3": 2.43,
"Value4": 2.4537,
"Count": 1
}
]
}
]
输出中的GroupIndex
字段来自具有值的第一行。随后的行已删除但已计数。
当然我可以使它成为单个LINQ查询。第二个查询可能只包含第一个查询的分组...但是我认为这种方式更容易阅读。
答案 1 :(得分:2)
您可以使用LINQ
来执行此操作。它还可以处理输出中的重复项。我将它们放入List<List<string>>
中,因为我们不知道要创建多少个列表。
这可能适用于n
数量的Lists
,但是我还没有真正测试过。
// // Get all lines from File
var allLines = File.ReadAllLines("..\\..\\Test.txt");
// Gets only the values in the second column and groups by it. (Removing duplicates).
var groups = allLines.Distinct().GroupBy(line => line.Split(' ')[1]);
// This is your output. Put it in a List of Lists for unknown size
List<List<string>> lists = new List<List<string>>();
// Basically, for each group select then lines from the
// file where the second column matches the group.
foreach(var group in groups)
{
lists.Add(allLines.Select(lines => lines).Where(groupNum => groupNum.Split(' ')[1] == group.Key).ToList());
}
// Print out stuff
foreach(List<string> container in lists)
{
Console.WriteLine("List: " + container.First().Split( ' ')[1]);
foreach(string individualString in container)
{
Console.WriteLine(individualString);
}
}
输入:
001 000 2.59 2.4595 2.4573 2.62
001 000 2.59 2.4595 2.4573 2.62 // Duplicate
001 000 2.59 2.4595 2.4573 2.62 // Duplicate
001 001 1.56 1.52 1.51 1.56
001 002 0.67 0.66 0.66 0.67
001 003 0.5 0.4949 0.49 0.5
001 004 0.96 0.9601 0.96 0.9601
001 005 0.5291 0.5001 0.5 0.54
002 000 2.4537 2.4422 2.43 2.4537
002 003 0.5 0.51 0.4945 0.515
002 005 0.5 0.4801 0.4801 0.5
003 000 2.43 2.3399 2.3399 2.43
003 003 0.5101 0.5087 0.5005 0.5289
003 004 1 0.998 0.98 1
001 005 0.49 0.4802 0.4362 0.49
001 006 0.49 0.4802 0.4362 0.49
001 005 0.49 0.4802 0.4362 0.49 // Duplicate
003 008 0.49 0.4802 0.4362 0.49
001 009 0.49 0.4802 0.4362 0.49
产生:
List: 000
001 000 2.59 2.4595 2.4573 2.62
001 000 2.59 2.4595 2.4573 2.62
001 000 2.59 2.4595 2.4573 2.62
002 000 2.4537 2.4422 2.43 2.4537
003 000 2.43 2.3399 2.3399 2.43
List: 001
001 001 1.56 1.52 1.51 1.56
List: 002
001 002 0.67 0.66 0.66 0.67
List: 003
001 003 0.5 0.4949 0.49 0.5
002 003 0.5 0.51 0.4945 0.515
003 003 0.5101 0.5087 0.5005 0.5289
List: 004
001 004 0.96 0.9601 0.96 0.9601
003 004 1 0.998 0.98 1
List: 005
001 005 0.5291 0.5001 0.5 0.54
002 005 0.5 0.4801 0.4801 0.5
001 005 0.49 0.4802 0.4362 0.49
001 005 0.49 0.4802 0.4362 0.49
List: 006
001 006 0.49 0.4802 0.4362 0.49
List: 008
003 008 0.49 0.4802 0.4362 0.49
List: 009
001 009 0.49 0.4802 0.4362 0.49
如果要从输出中删除重复项,只需将.Distinct()
中的var groups
调用移到File.ReadAllLines()
上。
答案 2 :(得分:1)
您可以使用System.IO.File.ReadLines()
读取每一行,并用空格分隔,并将这些行存储在键值为PyObject*
的键值中,其中键为第二列。
演示:
Dictionary<string, List<string>>
输出:
using System;
using System.Collections.Generic;
namespace StackOverFlow {
public static class Program {
# Store everything here
private static Dictionary<string, List<string>> data = new Dictionary<string, List<string>>();
public static void Main(string[] args) {
// Read all lines into array
string[] lines = System.IO.File.ReadAllLines(@"Log.txt");
foreach (string line in lines) {
// Split line by whitespace
string[] columns = line.Split(' ');
// Key is second column
string key = columns[1];
// Add line to dictionary, also making sure list is initialised
if (!data.ContainsKey(key)) {
data.Add(key, new List<string>());
}
data[key].Add(line);
}
// Print out results
foreach (KeyValuePair<string, List<string>> entry in data) {
Console.WriteLine(entry.Key);
foreach (string line in entry.Value) {
Console.WriteLine(line);
}
Console.WriteLine();
}
}
}
}