请在修复日期之前删除项目,并替换第一次出现的问题

时间:2018-11-26 13:37:32

标签: c#

基于诸如

的类型化类的列表
class CostCenter
{
    string center;
    string percentage;
    DateTime start;
}

我有以下这些元素的列表:

  • {“ a”,70,“ 2019/11/10”}
  • {“ b”,30,“ 2019/11/10”}
  • {“ A”,40,“ 2018/10/05”}
  • {“ B”,60,“ 2018/10/05”}
  • {“ xx”,10,“ 2010/01/01”}
  • {“ yy”,90,“ 2010/01/01”}
  • {“ 100”,50,“ 2009/07/03”}
  • {“ 101”,50,“ 2009/07/03”}

考虑到我要删除所有开始日期早于或等于固定日期(list)的元素(_earliestDate),因此此固定数据还将替换最早的比赛。在此示例中,最早的日期是“ 2010/11/01”,因此将“ xx”和“ yy”的开始日期替换为“ 2010/11/01”。 输出应如下所示:

  • {“ a”,70,“ 2019/11/10”}
  • {“ b”,30,“ 2019/11/10”}
  • {“ A”,40,“ 2018/10/05”}
  • {“ B”,60,“ 2018/10/05”}
  • {“ xx”,10,“ 2010/11/01”}
  • {“ yy”,90,“ 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;
    }   
}

dateToReplaceearliestFound将用作代码中的标志,以确定何时循环。

以某种方式我认为这不是最好的选择,您对如何使其更容易理解或有效有任何建议吗?

5 个答案:

答案 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;
    }
}