【问题标题】:Find "Active" items in a list not followed by "InActive" Items在列表中查找“活动”项目之后没有“非活动”项目
【发布时间】:2016-07-14 17:05:28
【问题描述】:

我有一个清单

 public class CarRent
    {
        public string Brand { get; set; }
        public string Status { get; set; }
        public DateTime Date { get; set; }
    }
  var mylist = new List<CarRent>() {
                new CarRent() { Brand = "Toyota",Date=DateTime.Parse( "1/10/14"),Status="Active" },//1
                new CarRent() { Brand = "Honda",Date=DateTime.Parse( "5/3/14"),Status="Active" },//2
                new CarRent() { Brand = "Toyota",Date=DateTime.Parse( "6/28/14"),Status="InActive" },//3
                new CarRent() { Brand = "Toyota",Date=DateTime.Parse( "12/12/14"),Status="Active" },//4
                new CarRent() { Brand = "Honda",Date=DateTime.Parse( "12/14/14"),Status="InActive" },//5
                new CarRent() { Brand = "Ford",Date=DateTime.Parse( "3/22/15"),Status="Active" },//6
                new CarRent() { Brand = "Ford",Date=DateTime.Parse( "12/12/15"),Status="InActive" },//7
                 new CarRent() { Brand = "Ford",Date=DateTime.Parse( "6/15/16"),Status="Active" },//8
            };

我需要在列表中找到状态为“活动”且后面没有“不活动”状态的项目。 例如:第 1 项 - 品牌“Toyota”和状态“活跃”之后是相同品牌的第 3 项、较晚日期和“非活跃”,但具有“活跃”状态和日期的同一品牌第 4 项大于第 1 项和第 3 项并且没有同品牌的后续“Inactive”状态。所以第 4 项是合格的。

从上面的列表中,预期的结果是第 4 项和第 8 项。

我该怎么做?

【问题讨论】:

  • 同品牌的商品?
  • 那么,第一项(“Toyota”,Active)后跟(“Honda”,Active)是否也符合条件?我的意思是,您只比较同一品牌的商品吗?
  • 第一个项目(“Toyota”,Active)后跟(“Honda”,Active)不符合条件。我需要比较同一品牌的项目
  • 同一品牌的两个“活跃”状态之间可以没有“不活跃”吗?即“活动”和“非活动”状态是否切换?在您的示例中,上述内容成立。
  • 我可以有两个相同品牌的“活跃”状态,中间没有“不活跃”

标签: c# linq collections


【解决方案1】:

如果您只希望在它们之后没有“InActive”的 Active 项目可以在字典中创建列表,并在获得“InActive”状态时清除,然后选择缓存中的所有值完成迭代

var cache = new Dictionary<string,List<CarRent>>();

for(int i=0; i<myList.Count; i++)
{
    var curr = myList[i];

    if(!cache.ContainsKey(curr.Brand))
    {
        cache[curr.Brand]=new List<CarRent>();
    }

    if(curr.Status == "InActive")
        cache[curr.Brand].Clear();

    else if(curr.Status == "Active")
        cache[curr.Brand].Add(curr);

}

var results = cache.Values.SelectMany(a=>a);

【讨论】:

  • 此解决方案适用于问题中的列表以及是否有两个相同品牌的“活动”项目。
【解决方案2】:

这是最简单的方法:

var results = mylist.GroupBy(x => x.Brand)
                .Select(x => x.LastOrDefault())
                .Where(x => x.Status == "Active").ToList();

只有在“活跃”时,您才需要每个品牌的最后一项。

【讨论】:

  • 它不处理有效项目(或项目)可以出现在一组品牌中的情况。如:“活跃”“不活跃”“活跃”“不活跃”“活跃”。
  • @ItayPodhajcer 这似乎不是 OP 的要求。
  • 此解决方案适用于问题中的列表和场景“每个品牌的最后一项仅当它是“活动”时”。如果有两个相同品牌的“活动”项目(将新项目添加到列表 new CarRent() { Brand = "Toyota",Date=DateTime.Parse("12/13/16"),Status="Active" }, //9) 这将返回两个“活动”项目的最新日期
【解决方案3】:

你去吧:

var result =
    (from rent in mylist
     group rent by rent.Brand into brandRents
     let lastInactive = brandRents
        .Where(r => r.Status == "InActive")
        .DefaultIfEmpty()
        .Aggregate((rent1, rent2) => rent2.Date > rent1.Date ? rent2 : rent1)
     from rent in brandRents
     where rent.Status == "Active" && 
        (lastInactive == null || rent.Date > lastInactive.Date)
     select rent).ToList();

您按品牌对列表进行分组,然后为每个组找到最新的非活动元素(如果有)并选择其后的所有活动元素。

它的功能可能看起来很复杂,但 LINQ 不太适合处理序列元素关系。

【讨论】:

    【解决方案4】:

    试试这个:

    var filteredList = mylist
        .OrderBy(item => iten.Date)
        .GroupBy(item => item.Brand)
        .SelectMany(itemsGroup => itemsGroup.Where((item, index) => item.Status == "Active" &&
            mylist.ElementAtOrDefault(index + 1)?.Status != "InActive");
    

    希望对你有帮助!

    【讨论】:

    • 错误:操作员 '??'不能应用于“bool”和“bool”类型的操作数
    • 这将返回第 2 项。预期为第 4 项和第 8 项
    • 删除ThenByWhere 中的品牌检查更新了答案。
    • 在搜索有效商品之前更新了按品牌对商品进行分组的答案。
    • == "InActive" 更改为 != "InActive",应该可以解决问题!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多