2017-07-19 130 views
2

我有数值的列表,每个日期,就像这样:LINQ中的ForEach循环如何知道以前的循环迭代中的值?

Date  Value 
-------- ----- 
3/5/2017 2 
3/6/2017 2 
3/7/2017 3 
3/8/2017 3 
3/9/2017 3 
3/10/2017 4 

你可以看到,我们在“2”了两天,然后升级到“3”三天,然后得第四天“4”。

使用LINQ,很容易表现上,我们取得了创纪录的日期:

values.GroupBy(x => x.Value).OrderBy(x => x.Key).ToList().ForEach(x => 
{ 
    var record = x.OrderBy(x1 => x1.Date).First(); 
    Console.WriteLine(
     $"New record of {x.Key} on {record.Date.ToShortDateString()}" 
    ); 
}); 

此输出:

New record of 2 on 3/5/2017 
New record of 3 on 3/7/2017 
New record of 4 on 3/10/2017 

这是伟大的,但如果我想这样做的:

New record of 2 on 3/5/2017 
New record of 3 on 3/7/2017 (took 2 days) 
New record of 4 on 3/10/2017 (took 3 days) 

ForEach循环的每个迭代将要知道最后一个值的值以便计算差异。这将如何成为可能?

答:

答案在下面选择,但这里是用我的实际执行Aggregate

values.OrderBy(x => x.Date).Aggregate((a, b) => 
{ 
    if (b.Value > a.Value) 
    { 
     $"New record of {b.Value} on {b.Date.ToShortDateString()} (took {b.Date.Subtract(a.Date).Days} day(s))".Dump(); 
     return b; 
    } 
    return a; 
}); 

这个结果:

New record of 3 on 3/7/2017 (took 2 day(s)) 
New record of 4 on 3/10/2017 (took 3 day(s)) 

注意, “基线” 的2没有在那里列出,这对我的目的来说很好。

Aggregate的关键在于它可以写成功能性的工作,通过二元组中的枚举 - 两个组中的枚举。因此:

1,2 
2,3 
3,4 

在许多情况下,您将这两件事合并,然后返回组合。但没有任何理由你不能仅仅将比较,然后返回其中一个。这就是我所做的 - 我比较他们,然后返回新记录,如果它新记录,否则我返回现有记录。

+2

总结可以帮助你。 https://msdn.microsoft.com/en-us/library/bb549218(v=vs.110).aspx – PlayDeezGames

+1

LINQ似乎并不是解决这个问题的最好方法... – maccettura

+0

您是否尝试将其转换为'查找'而不是'List',然后获取项目数并写入控制台? –

回答

2

请考虑骨料:

values.Aggregate(new Tuple<int,int?>(0,null), (acc, e) => 
{ 
    if(acc.Item2==null) 
    { 
     Console.WriteLine($"New record of {e.Value} on {e.Date.ToShortDateString()}"); 
     return new Tuple<int, int?>(1, e.Value); 
    } 
    else 
    { 
     if(e.Value!=acc.Item2.Value) 
     { 
      Console.WriteLine($"New record of {e.Value} on {e.Date.ToShortDateString()} (took {acc.Item1} days)"); 
      return new Tuple<int, int?>(1, e.Value); 
     } 
     else 
     { 
      return new Tuple<int, int?>(acc.Item1+1, acc.Item2); 
     } 
    } 
}); 
+0

使用'Aggregate'是正确的答案,但我在上面的问题中提出了我的实际解决方案。 – Deane

+2

@deane如果你有更好的方法,你可以upvote PlayDeegames并接受你的解决方案作为一个答案它是可行的SO –

1

在LINQ查询中有几条冗余语句,这可能会导致性能问题。谢天谢地,虽然你不需要LINQ所有的东西。好“醇foreach仍然是有用的:

//Iterate through all groups 
foreach(var group in values.GroupBy(x => x.Value)) 
{ 
    //sort the records by date 
    var records = group.OrderBy(x => x.Date).ToList(); 

    //Grab the first record 
    var firstRecord = records.First(); 

    if(records.Count > 1) 
    { 
     //Gets diff in days between first and last 
     int dayCount = (firstRecord.Date - records.Last()).TotalDays; 
     Console.WriteLine($"New record of {firstRecord.Key} on {firstRecord .Date.ToShortDateString()} took {dayCount} days"); 
    } 
    else 
    {    
     Console.WriteLine($"New record of {firstRecord.Key} on {firstRecord .Date.ToShortDateString()}"); 
    }   
} 
+0

我认为你对OP的目标有点过了,这里的挑战是明确在linq做这个! –