LINQ的Group by未返回预期结果。

huangapple go评论56阅读模式
英文:

LINQ Group by doesn't return the result as expected

问题

我有一个动物类:

public class Animals
{
    public string Type { get; set; }
    public string Gender { get; set; }
    public int Amount { get; set; }
}

以及一个与不同动物相关的成本类:

public class Cost 
{
    public string AnimalType { get; set; }
    public int Cost { get; set; }
}

我有一个不同类的列表:

List<Animals> animalList = new List<Animals>()
{
     new Animals() { Type = "Wolf", Gender = "Female", Amount = 10 },
     new Animals() { Type = "Wolf", Gender = "Male", Amount = 20 },
     new Animals() { Type = "Lion", Gender = "Female", Amount = 10 }, 
     new Animals() { Type = "Horse", Gender = "Male", Amount = 5 }
};

List<Cost> cost = new List<Cost>() 
{
    new Cost() { AnimalType = "Wolf", Cost = 1000 },
    new Cost() { AnimalType = "Lion", Cost = 2000 }, 
    new Cost() { AnimalType = "Horse", Cost = 1500 }
}

我想对每种动物的成本进行求和,得到如下结果:

AnimalType Cost
Wolf 30000
Lion 20000
Horse 7500

我尝试使用 LINQ 和如下方式进行求和:

var totalCost = from animal in animalList 
      join cost in costList 
      on animal.Type equals cost.AnimalType 
      group animal by animal.Type into g
      select g;

但这只返回了 Wolf(可能是因为它是唯一有两种性别的动物),但我不明白为什么。我该如何编写 select 来找到我想要的结果?

英文:

I have an animal class:

public class Animals
{
    public string Type { get; set; }
    public string Gender { get; set; }
    public int Amount { get; set; }
}

and a class Cost for the cost associated with the different animals:

public class Cost 
{
    public string AnimalType { get; set; }
    public int Cost { get; set; }
}

I have a list of the different classes:

List<Animals> animalList = new List<Animals>()
{
     new Animals() { Type = "Wolf", Gender = "Female", Amount = 10 },
     new Animals() { Type = "Wolf", Gender = "Male", Amount = 20 },
     new Animals() { Type = "Lion", Gender = "Female", Amount = 10 }, 
     new Animals() { Type = "Horse", Gender = "Male", Amount = 5 }
};

List<Cost> cost = new List<Cost>() 
{
    new Cost() { AnimalType = "Wolf", Cost = 1000 },
    new Cost() { AnimalType = "Lion", Cost = 2000 }, 
    new Cost() { AnimalType = "Horse", Cost = 1500 }
}

I want to sum the cost for each animals having a result like this:

AnimalType Cost
Wolf 30000
Lion 20000
Horse 7500

I've tried to use LINQ and sum like this:

var totalCost = from animal in animalList 
      join cost in costList 
      on animal.Type equals cost.AnimalType 
      group animal by animal.Type into g
      select g;

but this only returns Wolf (supposedly because it is the only one having two genders), but I don't understand why. How can I write the select to find what I am looking for?

答案1

得分: 5

问题是您当前的LINQ查询返回了animal数据(g)。

相反,在分组时,应构建一个包含animalcost数据的新数据集,以便您可以在投影中执行计算。

List<CostModel> costList = new List<CostModel>() 
{
	new CostModel() { AnimalType = "Wolf", Cost = 1000 },
	new CostModel() { AnimalType = "Lion", Cost = 2000 }, 
	new CostModel() { AnimalType = "Horse", Cost = 1500 }
};

var totalCost = (from animal in animalList 
		   join cost in costList 
		   on animal.Type equals cost.AnimalType 
		   group new { Animal = animal, Cost = cost } by animal.Type into g
		   select new 
			{
				AnimalType = g.Key,
				Cost = g.Sum(x => x.Cost.Cost * x.Animal.Amount)
			}).ToList();
public class CostModel 
{
    public string AnimalType { get; set; }
    public int Cost { get; set; }
}

尽管您的代码中存在一些错误:

  1. 在LINQ查询中,使用了join cost in costList,但没有声明costList变量。

  2. Cost类中将出现错误,因为有一个与类名冲突的Cost属性。

英文:

The problem is your current LINQ query returns the animal data (g).

Instead, when grouping, a new dataset containing animal and cost data should be constructed in order to allow you to perform the calculation in projection.

List&lt;CostModel&gt; costList = new List&lt;CostModel&gt;() 
{
	new CostModel() { AnimalType = &quot;Wolf&quot;, Cost = 1000 },
	new CostModel() { AnimalType = &quot;Lion&quot;, Cost = 2000 }, 
	new CostModel() { AnimalType = &quot;Horse&quot;, Cost = 1500 }
};

var totalCost = (from animal in animalList 
		   join cost in costList 
		   on animal.Type equals cost.AnimalType 
		   group new { Animal = animal, Cost = cost } by animal.Type into g
		   select new 
			{
				AnimalType = g.Key,
				Cost = g.Sum(x =&gt; x.Cost.Cost * x.Animal.Amount)
			}).ToList();
public class CostModel 
{
    public string AnimalType { get; set; }
    public int Cost { get; set; }
}

While there are few errors in your code:

  1. In the LINQ query, join cost in costList but there is no declaration for the costList variable.

  2. You will get error in Cost class as there is Cost property which clash the class name.

答案2

得分: 1

也许使用一个成本的字典会更好:

Dictionary<string, int> cost = new Dictionary<string, int>()
{
    {"Wolf", 1000 },
    {"Lion", 2000 },
    { "Horse", 1500 }
};

然后你可以使用以下的LINQ查询:

var result = animalList
     .GroupBy(x => x.Type)
     .Select(x => new { AnimalType = x.Key, Amount = cost[x.Key] * x.Sum(y => y.Amount)})
     .ToList();

请注意,如果动物类型中的某个不在字典中,该代码将引发异常。如果你不想要异常,你也可以插入一个条件:

var result = animalList
      .Where(x => cost.ContainsKey(x.Type))
      .GroupBy(x => x.Type)
      .Select(x => new { AnimalType = x.Key, Amount = cost[x.Key] * x.Sum(y => y.Amount)})
      .ToList();

在线演示:https://dotnetfiddle.net/B5gOaG

英文:

Maybe a dictionary for the cost would be better:

Dictionary&lt;string,int&gt; cost = new Dictionary&lt;string,int&gt; () 
{
    {&quot;Wolf&quot;, 1000 },
    {&quot;Lion&quot;, 2000 }, 
    { &quot;Horse&quot;, 1500 }
};

Then you can use the following LINQ query:

var result = animalList
     .GroupBy(x =&gt; x.Type)
     .Select(x =&gt; new { AnimalType = x.Key, Amount = cost[x.Key] * x.Sum(y =&gt; y.Amount)})
     .ToList();

Note that the code will throw an exception if one of the animal types is not in the dictionary. If you don't want that, you can also insert a where clause:

var result = animalList
      .Where(x =&gt; cost.ContainsKey(x.Type))
      .GroupBy(x =&gt; x.Type)
      .Select(x =&gt; new { AnimalType = x.Key, Amount = cost[x.Key] * x.Sum(y =&gt; y.Amount)})
      .ToList();

Online-demo: https://dotnetfiddle.net/B5gOaG

答案3

得分: -1

  • 根据您的代码,您需要更改 Cost 类中的属性名称 Cost。
    (我将其更改为 cost)

  • 创建一个名为 CostModel 的新类。

    public class CostModel
    {
        public string Animal { get; set; }
        public int Cost { get; set; }
    }
  • 尝试这段代码
    var totalCost = (from animal in animalList
                     join cost in costList
                     on animal.Type equals cost.AnimalType
                     group new { Animal = animal, Cost = cost } 
                     by animal.Type into g
                     select new CostModel
                     {
                         Animal = g.Key,
                         Cost = g.Sum(x => x.Cost.cost * x.Animal.Amount)
                     }).ToList();
    
    
    foreach(var cost in totalCost)
    {
        Console.WriteLine(cost.Animal.ToString() + ":" + cost.Cost);
    }
英文:
  • As per your code, you have to change the property name Cost in Cost class.
    (I changed it into cost)

  • Create new class as CostModel.

    public class CostModel
    {
        public string Animal { get; set; }
        public int Cost { get; set; }
    }
  • Try this code
    var totalCost = (from animal in animalList
                     join cost in costList
                     on animal.Type equals cost.AnimalType
                     group new { Animal = animal, Cost = cost } 
                     by animal.Type into g
                     select new CostModel
                     {
                         Animal = g.Key,
                         Cost = g.Sum(x =&gt; x.Cost.cost * x.Animal.Amount)
                     }).ToList();
    
    
    foreach(var cost in totalCost)
    {
        Console.WriteLine(cost.Animal.ToString() + &quot;:&quot; + cost.Cost);
    }

huangapple
  • 本文由 发表于 2023年6月26日 09:09:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/76552994.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定