Reputation: 3772
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.
Upvotes: 0
Views: 1904
Reputation: 660098
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?
Upvotes: 5
Reputation: 37020
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.
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:
Vector2 cheapestCellPosition = openCells
.OrderBy(cell => GetCostToTarget(cell, targetPosition) +
GetCell(cell).Cost.GetValueOrDefault())
.First();
Upvotes: 0
Reputation: 45135
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. This is not a Vector2
.
At the end when you use First
you are still selecting the first of those anonymous objects. It's not a Vector2
, so you can't assign it to a variable of type Vector2
.
But if you just change it to:
.First().Vector2
That will get the Vector2
property of the first anonymous object you selected. This is a Vector2
, so it should be assignable to 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
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
Upvotes: 3