【问题标题】:Need Lambda query with if depending on the values需要 Lambda 查询是否取决于值
【发布时间】:2017-11-07 15:56:21
【问题描述】:

我想 Lambda 我的代码,但卡住了。

基本上: 如果数组对象包含 4 个具有自己年份规范和 ID 的成员。然而,该数组可以包含更多具有相同和不同 Id 和年份的成员(但绝不会具有相同的 Id 和相同年份)。

成员数组:

array[0]: Id 1 Year 2010
array[1]: Id 2 Year 2010
array[2]: Id 1 Year 2008
array[3]: Id 1 Year 2009

首先 - 如果数组中还有另一年(相同的 ID,不同的年份),我想删除 2010 年具有特定 ID 的所有数组成员。所以在这种情况下,我想删除 [0] 而不是其他成员。

其次—— 在这种情况下,我只想保留 2010 年之后的下一个最新年份,即 2009 年的 ID 1,这意味着我也想删除 [2]。 (年份以字符串形式出现,这就是为什么我将它们转换为整数以便在下面的代码中进行比较)

下面是我的 for 循环代码,我需要 Lambda 专家帮助来避免循环:

var x = Member.Length;

for (int i = 0; i < x; i++)
{
    var y = Member[i].id;
    for (int j = i; j < x; j++)
    {
        var z = Member[j].id;
        if (i != j)
        {
            if (y == z)
            {
                if (Member[i].year == "2010") 
                {
                    Member = Member.Where(w => w != Member[i]).ToArray();
                    i--;
                    j--;
                    x--;
                    break;
                }

                var tempI = Convert.ToInt32(Member[i].year);

                var tempJ = Convert.ToInt32(Member[j].year);

                if (tempI > tempJ)
                {
                    Member = Member.Where(w => w != Member[j]).ToArray();
                    i--;
                    j--;
                    x--;
                    break;
                }
            }
        }
    }
}

【问题讨论】:

  • “下面是我的代码,其中的 for 循环可以工作,我需要 Lambda 专家的帮助来避免循环” 为什么您认为 Linq 会做得不同甚至更好?通常它所做的一切都是为了隐藏复杂性,这是一件坏事。您不应该使用您不理解的代码使您的代码过于复杂。而是努力寻找易于理解的工作代码。
  • 要访问@HimBromBeere,请使用您所知道的。如果你所拥有的东西有效,那就坚持下去,直到你对其他东西感到满意为止。可能性很好,其他东西只会清理外观(即更少的代码行),但几乎没有简化它。
  • @gilliduck “可能性很好,其他东西只会清理外观......”嗯,嗯,是的。这就是你如何让你的代码更容易阅读的方式,尤其是对于那些实际上没有编写它的人。学习编写干净的代码永远不会太早,无论是 LINQ 还是本机控制流。
  • @KennethK。短代码!=干净的代码。如果您不知道某个部分的作用,那么冗长和冗长可能会带来巨大的好处。我有一个(前)同事,他喜欢聪明并编写无法弄清楚的短代码。比起他聪明的“干净”代码,我更喜欢冗长的循环。
  • 我只想保留 2010 年之后的下一个最新年份 你能详细说明一下吗? 2009 年在 2010 年之前你是指最接近还是最高?

标签: c# arrays linq lambda calculation


【解决方案1】:

我同意这个要求没有多大意义,但这就是我的解释

var Member = new[]
           {
               new { id = 1, year = "2010" },

               new { id = 2, year = "2010" } ,

               new { id = 1, year = "2008" } ,

               new { id = 1, year = "2009" }  
           };

           var results = from item in Member.Select(x => new { x.id, Year = Convert.ToInt32(x.year), item = x })
                         group item by item.id into sameItems
                         let order = sameItems.OrderByDescending(x => x.Year)
                         let first = order.ElementAtOrDefault(0)
                         let second = order.ElementAtOrDefault(1)
                         select first.Year == 2010 && second != null ? second.item : first.item;

            foreach (var item in results)
            {
                System.Console.WriteLine($"id:{item.id},year:{item.year}");
            }        

【讨论】:

    【解决方案2】:

    我倾向于避免使用 LINQ 来更改我正在查询的基础集合。 下面的代码将为每个成员选择最多两个最近的条目。

    var result = new List<MemberClass>();
    var groups = Member.OrderBy(m => m.Id).ThenByDescending(m => m.Year).GroupBy(m => m.Id).ToList();
    groups.ForEach(c => result.AddRange(c.Take(2)));
    

    使用result 代替原来的数组。

    我不知道性能是否是您的考虑因素。随着您的收藏增加,上面的代码可能会变慢。

    【讨论】:

      【解决方案3】:

      您的描述和要求不兼容,但这是一种解释:

      public class Member
      {
          public int Id { get; set; }
          public string Year { get; set; }
      }
      
      var items = (new List<Member>() {
          new Member() { Id=1, Year="2010" },
          new Member() { Id=2, Year="2010" },
          new Member() { Id=1, Year="2008" },
          new Member() { Id=1, Year="2009" }
      }).ToArray();
      
      // Group everythnig by year, then only keep the highest id
      var firstFiltered = items
          .GroupBy(
              x => x.Year,
              x => x.Id,
              (year, ids) => new Member()
                              {
                                  Id = ids.Last(),
                                  Year = year
                              });
      
      var secondFiltered = firstFiltered
          // Only keep years before 2010
          .Where(x => String.Compare(x.Year, "2010") == -1)
          // Then order by Id then Year
          .OrderBy(x => x.Id)
          .ThenBy(x => x.Year)
          // And only keep the last/most recent year
          .GroupBy(
              x => x.Id,
              x => x.Year, 
              (id, years) => new Member() 
                              {
                                  Id = id,
                                  Year = years.Last()
                              });
      

      【讨论】:

        猜你喜欢
        • 2017-07-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-11-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-04
        相关资源
        最近更新 更多