首页 > 解决方案 > create new object within C# Linq syntax on Select

问题描述

I have a list of Vector2 objects. 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

How can I fix this? I need to setup the Value property based on the current element.

标签: c#linq

解决方案


UPDATE: You are using this to implement the A-star algorithm. 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. Can you genericize MinBy further, so that it can take any cost function?


推荐阅读