根据N个值中的哪一个返回不同的结果是最小的

时间:2012-08-06 17:50:03

标签: c#

不确定如何使标题更具描述性,所以我将从一个例子开始。我正在使用下面的代码,从枚举中选择一个方向,这取决于四个轴中哪一个与给定方向相比形成最小角度。

static Direction VectorToDirection(Vector2 direction)
{
    double upDiff = System.Math.Acos(Vector2.Dot(direction, -Vector2.UnitY));
    double downDiff = System.Math.Acos(Vector2.Dot(direction, Vector2.UnitY));
    double leftDiff = System.Math.Acos(Vector2.Dot(direction, -Vector2.UnitX));
    double rightDiff = System.Math.Acos(Vector2.Dot(direction, Vector2.UnitX));

    double smallest = System.Math.Min(System.Math.Min(upDiff, downDiff), System.Math.Min(leftDiff, rightDiff));

    // This is the part I'm unsure about i.e.
    // Comparing smallest with each value in turn
    // To find out which of the four was "selected"
    if (smallest == upDiff) return Direction.Up;
    if (smallest == downDiff) return Direction.Down;
    if (smallest == leftDiff) return Direction.Left;
    return Direction.Right;
}

但是我在最后得到了关于浮点平等的Resharper警告。由于Min的实现,我猜它不应该是一个问题,但是想知道是否有更好的习惯用来解决这类问题除了比较 {{1}与每个原始值。

9 个答案:

答案 0 :(得分:2)

此代码可以为您提供所需的结果。

    if ((Math.Abs(direction.x) >= Math.Abs(direction.y))
      return direction.x >= 0 ? Direction.Right : Direction.Left;
    return direction.y >= 0 ? Direction.Up : Direction.Down;

答案 1 :(得分:1)

您可以制作<double ,Direction> sort the dictionary 字典,并使用正确的枚举获取最小值。

答案 2 :(得分:1)

可以定义一个包含diff和与之关联的值的类。 然后从这些对象中创建一个集合,并按差异对它们进行排序。之后 返回与第一个元素关联的值。

但是,在你的情况下,我不会去那里,代码很清楚。如果可能值的数量要大得多(或者事先不知道),那么我才会寻求更通用的解决方案。

答案 3 :(得分:1)

你能写一些if语句吗?

if  (upDiff < leftDiff && upDiff < downDiff && upDiff < rightDiff) return Direction.Up;
if  (leftDiff < upDiff && leftDiff < downDiff && leftDiff < rightDiff) return Direction.Left;
if  (rightDiff < leftDiff && rightDiff < upDiff && rightDiff < downDiff) return Direction.Right;
return Direction.Down;

也许它可以进一步清理,但这似乎是直截了当的。

答案 4 :(得分:1)

我会将所有选项放在一个数组中并找到min index。对于4种选择,排序可能是过度杀伤。如果此代码的执行很重要 - 请确保测量不同变体的时间。

以下未编译的代码:

static Direction VectorToDirection(Vector2 direction)
{
  var directions = new Direction[]{
    Direction.Up, Direction.Down, Direction.Right, Direction.Left };
  var unit = new Vector2[] {
   -Vector2.UnitY, Vector2.UnitY, Vector2.UnitX,-Vector2.UnitY};

  var minAngle = 10;
  var minIndex = -1;
  for(var index = 0; index < directions.length; index++)
  {
    double diff = System.Math.Acos(Vector2.Dot(direction, unit[index]));
    if (diff < minAngle)
    { 
      minAngle = diff;
      minIndex = index;
    }

  return directions[minIndex];
}

答案 5 :(得分:1)

static Direction VectorToDirection(Vector2 direction)
{
    var mappings = new[]
    {
        new { Direction = Direction.Up, Axis = -Vector2.UnitY },
        new { Direction = Direction.Down, Axis = Vector2.UnitY },
        new { Direction = Direction.Left, Axis = -Vector2.UnitX },
        new { Direction = Direction.Right, Axis = Vector2.UnitX }
    };
    return mappings.OrderBy(m => Math.Acos(Vector2.Dot(direction, m.Axis))).Select(m => m.Direction).First();
}

Linq方式。这没有经过测试,但你应该得到它。

答案 6 :(得分:0)

设置不准确

if ((Math.Abs(smallest - upDiff) < 0.00001) return Direction.Up;

答案 7 :(得分:0)

你正在做,我认为不会有任何错误。但是,如果您将来最终重构或更改代码,则可能会遇到一些问题。

为了安全起见,只需做一下resharper的建议。

答案 8 :(得分:0)

我通常使用switch代替if-else(至少3条款) - 有点简洁和快捷。

switch(smallest) {
  case upDiff: return Direction.Up;
  case downDiff: return Direction.Down;
  case leftDiff: return Direction.Left;
  default: return Direction.Right; 
}