简体   繁体   English

在选择时使用C#Linq语法创建新对象

[英]create new object within C# Linq syntax on Select

I have a list of Vector2 objects. 我有一个Vector2对象列表。 I want to select a value from each element and sort these values. 我想从每个元素中选择一个值并对这些值进行排序。 After that, I want to get the lowest value. 在那之后,我想获得最低的价值。

Vector2 cheapestCellPosition = openCells.Select(x => new {
        Vector2 = x,
        Value = GetCostToTarget(x, targetPosition) + GetCell(x).Cost.GetValueOrDefault()
    })
    .OrderBy(x => x.Value)
    .First();

This code throws an error 此代码引发错误

CS0029 C# Cannot implicitly convert anonymous type: Sym.Vector2 Vector2, int Value to Sym.Vector2 CS0029 C#无法隐式转换匿名类型:Sym.Vector2 Vector2,将int值转换为Sym.Vector2

How can I fix this? 我怎样才能解决这个问题? I need to setup the Value property based on the current element. 我需要基于当前元素设置Value属性。

UPDATE: You are using this to implement the A-star algorithm. 更新:您正在使用它来实现A-star算法。 Though the approach you are using works, you will probably be better off if you implement a priority queue; 尽管您使用的方法可行,但如果实现优先级队列,您可能会更好。 you can get significant performance wins by doing so. 这样您就可以获得重大的性能胜利。


It's unclear why you are going to the trouble of creating a sequence of anonymous types in the first place; 目前尚不清楚为什么要首先创建一个匿名类型序列。 why not simply write: 为什么不简单地写:

Vector2 cheapestCellPosition = openCells
  .OrderBy(x => GetCostToTarget(x, targetPosition) + GetCell(x).Cost.GetValueOrDefault())
  .First();

?

Note that though this is more efficient than what you wrote, is not as efficient as it could be . 请注意,尽管这比您写的要有效,但效率却不如可能

What you really want is the smallest item in a set. 您真正想要的是集合中最小的项目。 Unfortunately, that is not an operation that is provided in the standard sequence library. 不幸的是,这不是标准序列库中提供的操作。

Let's fix that. 让我们修复它。

What we want to write is: 我们要写的是:

Vector2 cheapestCellPosition = openCells
  .MinBy(x => GetCostToTarget(x, targetPosition) + GetCell(x).Cost.GetValueOrDefault());

Let's suppose the cost is a double, to make it easier. 让我们假设成本是它的两倍,使其变得更容易。

static class Extensions 
{
  public static T MinBy(this IEnumerable<T> items, Func<T, double> cost) 
  {
    T minItem = default(T);
    double? minCost = null;
    foreach(T item in items) 
    {
      double current = cost(item);
      if (minCost == null || current < minCost)
      {
        minCost = current;
        minItem = item;
      }
    }
    if (minCost == null) throw InvalidOperationException();
    return minItem;
  }
}

And we're done. 我们完成了。 We don't have to sort a list to find the smallest item! 我们不必对列表进行排序即可找到最小的物品!

Exercise : Suppose the cost function does not return a double. 练习 :假设cost函数不返回double。 Can you genericize MinBy further, so that it can take any cost function? 您可以进一步对MinBy进行泛化,以便采用任何成本函数吗?

After this line: 在此行之后:

.Select(x => new { Vector2 = x, Value = GetCostToTarget(x, targetPosition) + GetCell(x).Cost.GetValueOrDefault() })

You have a collection of anonymous objects with Vector2 and Value properties. 您具有具有Vector2Value属性的匿名对象的集合。 This is not a Vector2 . 不是 Vector2

At the end when you use First you are still selecting the first of those anonymous objects. 最后,当您使用First您仍将选择那些匿名对象中的第一个 It's not a Vector2 , so you can't assign it to a variable of type Vector2 . 它不是Vector2 ,所以不能将其分配给Vector2类型的变量。

But if you just change it to: 但是,如果您将其更改为:

.First().Vector2

That will get the Vector2 property of the first anonymous object you selected. 这将获取您选择的第一个匿名对象的Vector2属性。 This is a Vector2 , so it should be assignable to cheapestCellPosition 一个Vector2 ,因此它应该可分配给cheapestCellPosition

Although it's not the easiest thing to read, but your error is telling you this: 虽然这不是最容易阅读的东西,但是您的错误告诉您:

CS0029 C# Cannot implicitly convert anonymous type: Sym.Vector2 Vector2, int Value to Sym.Vector2 CS0029 C#无法隐式转换匿名类型:Sym.Vector2 Vector2,将int值转换为Sym.Vector2

It's telling you it can't convert the anonymous type with a Vector2 property of type Sym.Vector2 and a Value property of type int to type Sym.Vector2 它告诉你它无法与转换匿名类型Vector2类型的财产Sym.Vector2Value类型的财产int输入Sym.Vector2

The problem is that you're selecting the anonymous type which has both a Vector2 property and a Value property, but then you're trying to assign the first one to a Vector2 type. 问题在于您正在选择同时具有Vector2属性和Value属性的匿名类型,但是随后您尝试将第一个属性分配给Vector2类型。

If openCells is indeed an IEnumerable<Vector2> , then you can just remove the Select and put your ordering code directly in the OrderBy clause, and then return the First one: 如果openCells确实是IEnumerable<Vector2> ,则只需删除Select并将订购代码直接放在OrderBy子句中,然后返回First一个:

Vector2 cheapestCellPosition = openCells
    .OrderBy(cell => GetCostToTarget(cell, targetPosition) + 
                     GetCell(cell).Cost.GetValueOrDefault())
    .First();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM