基于诸如
的类型化类的列表class CostCenter
{
string center;
string percentage;
DateTime start;
}
我有以下这些元素的列表:
考虑到我要删除所有开始日期早于或等于固定日期(list
)的元素(_earliestDate
),因此此固定数据还将替换最早的比赛。在此示例中,最早的日期是“ 2010/11/01”,因此将“ xx”和“ yy”的开始日期替换为“ 2010/11/01”。
输出应如下所示:
我创建了以下代码:
string dateToReplace = null;
bool earliestFound = false;
foreach (var item in list.OrderByDescending(x => DateTime.Parse(x.start)).ToList())
{
if (earliestFound) //already marked, safe to remove others
{
list.Remove(item);
continue;
}
if (!string.IsNullOrEmpty(dateToReplace)) //remaining matches
{
if (string.Equals(item.start, dateToReplace))
{
item.start = _earliestDate;
continue;
}
else
{
earliestFound = true;
list.Remove(item);
continue;
}
}
if (item.start <= _earliestDate) //first earliest or same, more required
{
dateToReplace = item.start;
item.start = _earliestDate;
}
}
dateToReplace
和earliestFound
将用作代码中的标志,以确定何时循环。
以某种方式我认为这不是最好的选择,您对如何使其更容易理解或有效有任何建议吗?
答案 0 :(得分:4)
要解决问题的第一部分:在给定日期之前删除项目。
亲吻是你最好的朋友。您可以在过滤后重新分配列表,或者根据谓词删除所有不需要的项目。
var inputs = new List<CostCenter> {
new CostCenter("a", "70", "2019/11/10"),
new CostCenter("b", "30", "2019/11/10"),
new CostCenter("A", "40", "2018/10/05"),
new CostCenter("B", "60", "2018/10/05"),
new CostCenter("xx","10", "2010/01/01"),
new CostCenter("yy", "90", "2010/01/01"),
new CostCenter("100", "50", "2009/07/03"),
new CostCenter("101", "50", "2009/07/03"),
};
var result1 = inputs.Where(x => x.start > DateTime.Parse("2010/01/01")).ToList();
var result2 = inputs.RemoveAll(x=> x.start <= DateTime.Parse("2010/01/01"));
答案 1 :(得分:2)
首先,您需要过滤掉所有过时的项目。然后,您可以选择最早的start
,然后将其全部替换为_earliestDate
。
if (list == null)
throw new ArgumentNullException(...);
// Get rid of unused items and sort:
var actual = list
.Where(item => item.start >= _earliestDate)
.OrderByDescending(item => item.start)
.ToArray();
// If there are no matching items, then return empty array or throw exception
// It depends on your requirements
if (actual.Length == 0)
return actual;
// Take the least date in resulted array...
var earliestInActual = actual[actual.Length - 1];
// ...and replace it with _earliestDate
for (int i = actual.Length - 1; i >= 0; i--)
{
if (actual[i].start != earliestInActual)
break;
item.start = _earliestDate;
}
return actual;
请记住,它将更改原始对象,因此start
日期也会在原始列表中更新。
答案 2 :(得分:1)
在使用foreach loop
的同时从列表中删除项目会导致其失去位置,但是您可以使用for loop
或执行另一个循环来删除所有已标记的项目。
DateTime cutOffDate = DateTime.Parse("2010/11/01");
List<CostCenter> removeList = new List<CostCenter>();
foreach (var item in list.OrderByDescending(x => x.start).ToList())
{
if (item.start <= cutOffDate) {
removeList.Add(item);
}
}
foreach(var remove in removeList)
{
if (list.Contains(remove)) {
list.Remove(remove);
}
}
答案 3 :(得分:1)
我们可以使用给定条件创建新的过滤列表
DateTime threshold = new DateTime(2010, 11, 01);
List<CostCenter> result = cc.Where(x => x.start.Date > threshold.Date).ToList();
POC:.netFiddle
答案 4 :(得分:1)
对于必须删除99%元素的列表,您当前将遍历整个列表以查找所有这些元素并将其删除。
不用清除列表,只需选择您不想要的部分,并在日期小于earliestDate
时停止。
使用“ TakeWhile
”方法,只需添加一个标志即可知道何时编辑该元素以确定日期。
public static IEnumerable<CostCenter> TakeWhileAndOneAfter
(IEnumerable<CostCenter> source, DateTime splitDate )
{
DateTime? earliestDate = null;
bool earliestFound = false;
foreach (CostCenter element in source)
{
if (!earliestFound && !(element.start > splitDate))
{
earliestFound = true;
earliestDate = element.start;
}
if (earliestFound)
{
if (element.start < earliestDate)
{
break;
}
else
{
element.start = splitDate;
}
}
yield return element;
}
}