首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >根据DateTime均衡数据行

根据DateTime均衡数据行
EN

Stack Overflow用户
提问于 2012-01-09 06:39:53
回答 2查看 186关注 0票数 2

这与我在SO上问的另一个问题类似,但它与它有很大的不同,以至于我还无法自己想出一个答案。我认为介绍我的问题的最好方法是用一张图片:

我有几个文本文件(本例中为4个),每个文件都有数百万行数据,格式如下:

代码语言:javascript
复制
TIME DATA

File #1
104500 4098
104501 34098
104502 1321
104502 3408
104503 4587
104503 1204
104503 49858
104504 1029
104505 4058
104506 7576

File #2
104500 23408
104500 2131
104501 5686
104502 6839
104502 21838
104503 86760
104503 20812
104503 85719
104504 4877
104505 2220
104506 4847

File #3
104500 23042
104501 12391
104501 5857
104501 6979
104502 2196
104502 21039
104503 9263
104503 50573
104503 18361
104504 17545
104505 67612
104506 21075

File #4
104500 1193
104501 8664
104502 1028
104502 68561
104503 69178
104503 1230
104503 12048
104504 8843
104505 9910
104506 53978
104506 13722

问题在于,一个文件中的给定时间可能比另一个文件中的数据条目更多或更少。例如,在上面的图片中,文件#1中只有一个条目对应于10:45:00,但在文件#2中有两个条目对应于10:45:00。我希望每个文件每次都有相同数量的行数,因此在我的文件#1和#2示例中,将在第一行“104500 4098”之后添加一个“填充”行,此填充行将是其上一行的精确副本(在本例中为104500 4098)。理想情况下,这些“填充”行应该插入到正在读取的文本文件中,而不是写入到新的文本文件中。

到目前为止,我想出的是我需要:

--计算每个给定时间的行数

--查找每个给定时间内哪个文件的行数最多

--在每个文件中必要的地方插入‘填充’行

不幸的是,我真的不知道该怎么做。我有一些想法,但这些想法在这一点上都很模糊,所以我真的不知道我应该读些什么。到目前为止,我想出的唯一真正的代码是,我可以使用Directory.GetFiles将目录中的所有文件分配给一个数组,然后我可以通过这种方式遍历所有文件,但这并不能让我走得很远。

这些数据行是由程序生成的,然后程序将这些行写入文本文件。我无法访问生成数据行的代码。

如果有人对我如何实现这一点有任何想法,我将不胜感激。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-01-09 07:31:33

让我们将这种情况归结为两个时间戳,我将提供答案。

下面我重新创建了三个文件。每个文件缓冲区都有104500和104501的时间戳,而第二个文件有两个501,表示为正在解决的问题。这意味着file1和file3只有一个501。然后,我模拟解析文件中的数据,并将它们投影到一个具有文件ID、数据和时间戳的类持有者中。一旦获取了每个文件缓冲区的所有数据,我就合并这些数据。将数据放在一个IEnumerable列表中,然后按时间分组;这是最终处理的关键,即分组。

现在,您所要做的就是提取感兴趣的时间单位,并在该集合上进行计算,同时记住file1和file3缺少的数据。然后,您可以对分组的结果进行操作,以便为丢失的结果添加更多的时间戳,或者只是弹出最后一个值。

答:无论如何,不要在文件中工作,将数据放在内存中,并在进行计算时调整为丢失的数据。

下面是数据的样子,看看它是如何通过104500和104501的时间方便地分组(键)的。一个只是从具有文件1-3的所有值的分组中提取目标时间,并进行计算。

下面是组织它的代码( dump方法来自Linqpad,它显示了我在图片中显示的数据)

代码语言:javascript
复制
void Main()
{
    string File1 = @"104500 1 
104501 1 
";

    string File2 = 
@"104500 2 
104501 2
104501 4
"; 

    string File3 = 
@"104500 5 
104501 5
"; 

    var ds3 = ExtractData(File1, 1).Union( ExtractData(File2, 2) )
                                   .Union( ExtractData(File3, 3))
                                   .GroupBy (d => d.Time );
    ds3.Dump();


}

public static IEnumerable<DataAndTime> ExtractData(string data, int fileID)
{

    string pattern = @"^(?<Time>[^\s]+)(?:\s+)(?<Data>[^\s]+)";

     return Regex.Matches(data, pattern, RegexOptions.Multiline)
                   .OfType<Match>()
                   .Select (m => new DataAndTime()
                                   { 
                                     FileID = fileID,
                                     Time = m.Groups["Time"].Value,
                                     Data = int.Parse(m.Groups["Data"].Value)
                                }
                                   );

}


// Define other methods and classes here

public class DataAndTime
{
   public int FileID { get; set; }
    public string Time { get; set; }
    public int Data { get; set; }

}

更新:在时间片提取

下面是将索引值提取到目标时间的代码。我认为这是一个时间碎片。当用户请求时间片时,代码必须足够智能,以便在所请求的索引(时间片)超出范围时将最后一个值识别为默认值。

例如,文件1有一个项目,如果我请求时间片索引2,它应该检索最后一个值,即第一个值。如果我请求索引100,它也应该返回该值。

所以让我们看看时间104501,并得到数据。然后,我们将按文件ID分组

代码语言:javascript
复制
var ds3 = ExtractData(File1, 1).Union( ExtractData(File2, 2) )
                               .Union( ExtractData(File3, 3))
                               .GroupBy (d => d.Time )
                               .First (d => d.Key == "104501")
                               .GroupBy (d => d.FileID) ;

我们的ds3数据如下所示:

现在我们需要创建一个方法,该方法将处理时间片的提取和丢失的索引(切片)值。为了做到这一点,我将使用DefaultIfEmpty来指定,如果我们要求太多,文件的最后一个值将是默认值。以下是代码

代码语言:javascript
复制
public static int ValueAtSnapshotSlice(int slice, IEnumerable<DataAndTime> data)
{
    var defaultData = data.Last();

    return data.Take(slice)
               .DefaultIfEmpty(defaultData)
               .Last().Data;

}

然后,如果我们查看文件2,并要求时间片1、2和3(偶数4+),但这并不存在,我们期望2、4、4、4作为结果值。下面是上面针对ds3的调用

代码语言:javascript
复制
ValueAtSnapshotSlice(1, ds3.First (d => d.Key == 2)); // 2
ValueAtSnapshotSlice(2, ds3.First (d => d.Key == 2)); // 4
ValueAtSnapshotSlice(3, ds3.First (d => d.Key == 2)); // 4
ValueAtSnapshotSlice(4, ds3.First (d => d.Key == 2)); // 4
票数 3
EN

Stack Overflow用户

发布于 2012-01-09 07:20:09

这不是一件简单的事情。对于初学者来说,您不能只在文本文件中插入一行。您需要将该文件复制到一个新文件中,并插入该过程中所需的行。然后,您可以删除旧文件,并重命名新文件以取代旧文件。

我还假设,在处理所有行之前,您不知道哪个文件需要添加行。这意味着您需要将所有文件加载到内存中,在内存中处理它们,并写出结果,或者在每个文件上打开一个流,并为每个文件打开一个新文件,然后根据需要插入行,将数据从旧流处理到每个文件的新流。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8782018

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档