我有一个struct
,其中包含一些int
和bool
成员,我希望从列表中获取最低值(实际上是进行A *搜索基于Path Finder)。
基本上,我的对象看起来像这样:
public struct Tile
{
public int id;
public int x;
public int y;
public int cost;
public bool walkable;
public int distanceLeft;
public int parentid;
}
我想获得距离最低的项目。列表声明如下:
List<Structs.Tile> openList = new List<Structs.Tile>();
以这种方式分配值:
while (pathFound == null)
{
foreach (Structs.Tile tile in map)
{
foreach (Structs.Tile tile1 in getSurroundingTiles(Current))
{
if (tile1.x == tile.x && tile1.y == tile.y)
{
Structs.Tile curTile = tile1;
curTile.parentid = Current.id;
curTile.distanceLeft = (Math.Abs(tile.x - goalx) + Math.Abs(tile.y - goaly));
if (curTile.distanceLeft == 0)
{
pathFound = true;
}
openList.Add(curTile);
}
}
}
foreach (Structs.Tile tile in openList)
{
}
}
如果我不得不猜测我会说这要么是非常困难,要么比我听起来要复杂得多,或者非常简单,我只是感到困惑。
我确实考虑过滚动列表并将每个项目与其较低的对应项进行比较,但考虑到我们所处的年龄,这似乎是不合理的,它似乎会有一种更简单的方式。我不关心列表的顺序,因为我正在为每个项目分配一个索引,我可以从中调用它。
提前致谢!
答案 0 :(得分:5)
其他答案解释了如何使用LINQ执行此操作 - 但是,它们都是O(n)
或更慢。使用其中一种方法将显着减慢您的寻路算法。
相反,应该使用适当的数据结构。您应该将节点存储在优先级队列中,而不是列表,以获取(并删除) O(log n)
中的最小值。
请参阅this question以获取.Net中的优先级队列列表。
答案 1 :(得分:2)
没有一个LINQ扩展方法返回具有最小值的对象,但您可以自己编写一个。以下类在任何非空的可枚举项上执行您想要的操作:
public static class MyExtensions
{
public static TSource MinOf<TSource>(
this IEnumerable<TSource> source,
Func<TSource, int> selector)
{
// Get the enumerator.
var enumerator = source.GetEnumerator();
if (!enumerator.MoveNext())
throw new InvalidOperationException("The source sequence is empty.");
// Take the first value as a minimum.
int minimum = selector(enumerator.Current);
TSource current = enumerator.Current;
// Go through all other values...
while (enumerator.MoveNext())
{
int value = selector(enumerator.Current);
if (value < minimum)
{
// A new minimum was found. Store it.
minimum = value;
current = enumerator.Current;
}
}
// Return the minimum value.
return current;
}
}
将它放在项目的一个文件中并按如下方式调用:
openList.MinOf(tile => tile.distanceLeft);
这比排序整个序列(使用OrderBy
)然后取第一个值(使用First
)更有效。
答案 2 :(得分:1)
要获得Tile
distanceLeft
最低Tile tile = openList.OrderByAscending(t => t.distanceLeft).First();
,请尝试以下操作:
IEnumerable<Tile>
修改强>
执行此操作将返回openList
,其将按升序排序 - {{1}}本身不会被修改。
答案 3 :(得分:1)
或者,如果由于某种原因你不能使用LINQ:
int lowest = 0;
for (int i = 1; i < openList.Count; ++i)
{
if (openList[i].distanceLeft < openList[lowest].distanceLeft)
{
lowest = i;
}
}
// lowest contains the index of the item with the lowest 'distanceLeft' value.
// You can return the item itself by indexing into the list.
var lowestItem = openList[lowest];