【问题标题】:Conditional Group and Select in LINQ with type conversion带有类型转换的 LINQ 中的条件组和选择
【发布时间】:2013-08-19 15:55:45
【问题描述】:

我知道这方面已经有很多问题了,但由于类型转换(我认为),我仍然无法让它工作。

我有一个自定义类列表,我通常根据用户选择按月 (mt) 或季度 (qr) 将其分组。这工作正常。但是,现在我请求允许按 Q413 和 2013 年剩余时间进行分组。 Mt 和 Qr 是字符串。 Quartpos 是双精度数,如果仅 Q4 以季度为单位且以月为单位,则等于 4。

这是我所拥有的:

List<MyClass> results = classlist
  .GroupBy(a => new { 
                a.rg,
                a.tar,
                a.mt = ((double.Parse(a.qr) < quartpos) ? a.mt : 0),
                a.qr })
  .Select(g => new MyClass { 
               RG = g.Select(a => a.rg).First(),
               tar = g.Select(a => a.tar).First(),
               yr = g.Select(a => a.yr).First(),
               qr = g.Select(a => a.qr).First(),
               mt = g.Select(a => a.mt).First(),
               pp = g.Average(a => double.Parse(a.pp)),
               pi = g.Sum(a => double.Parse(a.pi)),
               cp = g.Average(a => double.Parse(a.cp)),
               ci = g.Sum(a => double.Parse(a.ci)),
               it = g.Sum(a => double.Parse(a.it)),
               to = g.Sum(a => double.Parse(a.to)),
               cnt = g.Select(a => a.dt).Distinct().Count(),
               pdvol = g.Sum(a => (double.Parse(a.pp) <= 1) 
                                  ? 0 
                                  : (double.Parse(a.pi) / double.Parse(a.pp))) })
  .ToList();

这会引发两个错误:

  1. String Int 类型转换 - 因为 mt 是 string 但是:0 是 int

  2. 无效的匿名类型成员声明。

我完全清楚,如果按季度分组,我必须在选择中使用相同的语法,以确保如果按季度分组,则选择季度;如果也按山数分组,则选择月份。

类的定义:

public class Myclass
{
    public string yr;
    public string qr;
    public string mt;
    public string cw;
    public string tar;
    public string RG;
    public double pp;
    public double pi;
    public double cp;
    public double ci;
    public double it;
    public double to;
    public double pd;
    public double cd;
    public double fp;
    public double fi;
    public double fd;
    public int cnt;
    public double pdmw;
    public double pdvol;

}

classlist 是一个所有变量都是字符串的类 - 直接来自 csv 导入。

我的问题是如何有条件地对月份 (mt) 进行分组?

【问题讨论】:

  • 嗨,尼克,如果不知道什么是类列表类型,很难为您提供帮助。另外,发布类 MyClass 的定义
  • 为什么还要按字符串存储月份等? DateTime 会更好,甚至integer 会更好,您可能应该考虑将您的属性名称更改为更具描述性的名称(但这不是主题)。否决票可能是因为您没有包含问题,只是一个博客条目
  • @Sayse:它们是字符串,因为我从 csv 导入它们并尝试了各种方法,但是在导入时解析似乎比在 LINQ 聚合后解析慢很多,因为它是一个非常长的列表(1m 行)并且聚合后我只需要做一些解析
  • 很公平,但我很难相信,我想你的 csv 导入是一次性的,我想你会多次使用日期。
  • 您使用的是 API 还是对变量名长度施加限制的东西?如果不是,请使用更具描述性的变量名称。它将使您的代码更易于阅读和维护。

标签: c# linq


【解决方案1】:
a.mt = ((double.Parse(a.qr) < quartpos) ? a.mt : 0)

你不能像这样创建匿名类型。看看documentation中的语法。

任你选择:

a.mt

PropertyName = ((double.Parse(a.qr) < quartpos) ? a.mt : 0)

在这一行。

【讨论】:

    【解决方案2】:

    我能想到的一个不太优雅的解决方案是使用简单的.select(a =&gt; double.Parse(a.qr) &lt; quartpos)classlist 拆分为两个新列表,然后保留执行上述所有其他内容的代码,并将 list1 按月分组,将 list2 按季度分组.这将消除对条件分组的需要。

    但我认为一定有更好的方法。

            public static IEnumerable<EVFile> SmallerQ(this IEnumerable<EVFile> @this, double quarterpos)
        {
            return from ev in @this
                   where (double.Parse(ev.qr)<quarterpos)
                   select ev;
        }
    
        public static IEnumerable<EVFile> LargerEqQ(this IEnumerable<EVFile> @this, double quarterpos)
        {
            return from ev in @this
                   where (double.Parse(ev.qr) >= quarterpos)
                   select ev;
        }
    
    newlist =  classlist.SmallerQ(quarterpos).ToList();
    

    通过这两种扩展方法,我可以将原始列表一分为二,然后在没有条件组加入的情况下继续进行。所以它完成了这项工作,但正如所说的不是很好。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-02
      • 1970-01-01
      相关资源
      最近更新 更多