使用LINQ确定2个图表的相对位置

时间:2010-12-03 17:54:34

标签: c# linq math .net-3.5 diagram

我有两个点数组:double[] minusdouble[] plus,例如:

double[] minus = new[]
{
    24.043414306636713,
    26.521399902043807,
    23.049167719142361,
    24.473177606966754,
    18.238281854192408,
};

double[] plus = new[]
{
    8.31219054269323,
    9.5909890877229582,
    11.066525870449567,
    22.769068312057193,
    24.733540360065991,
};

我需要根据这个数字绘制2个图表并确定它们相对于彼此的位置:是否有一个交叉点,哪个是另一个?

我该怎么做? TIA

(请随意重新提出问题或更改主题,我不确定使用的数学术语是否合适)

编辑:这是一个Excel图表:

http://i.stack.imgur.com/NEhcs.png

很容易确定哪个在上面,哪个在哪​​里。

如何确定红色(加号)与蓝色(减号)的交叉点?使用LINQ?

6 个答案:

答案 0 :(得分:4)

要确定哪个更高,只需将minus [i]与plus [i]进行比较 - 无论哪个值越大,i处的“更高”值。

要确定交叉点,只需跟踪哪一个更高。当改变时,就会有一个交叉点。

修改

如果您无法追踪历史记录,那么:

if ((minus[i-1] > plus[i-1]) != (minus[i] > plus[i])) then
  // there was an intersection
else
  // there was not an intersection

答案 1 :(得分:4)

此代码可以找到所有碰撞:

double[] minus = new double[]
{
    3, 24, 26, 23, 25, 18, 5,  5,  1, 10,
};
double[] plus = new ![alt text][1]double[]
{
    3,  8,  9, 11, 22, 25, 5,  5,  3, 7
};

var collisionsBetweenIndices =
Enumerable.Range(1, minus.Length - 1)
          .Where(i => ((minus[i - 1] - plus[i - 1] < 0) && (minus[i] - plus[i] > 0)) ||
                      ((minus[i - 1] - plus[i - 1] > 0) && (minus[i] - plus[i] < 0)) ||
                      ((minus[i - 1] - plus[i - 1] == 0) && (minus[i] - plus[i] == 0)))
          .ToArray();

var collisionsOnIndices =
Enumerable.Range(0, minus.Length)
          .Where(i => minus[i] == plus[i])
          .ToArray();

foreach (var idx in collisionsBetweenIndices)
    Console.WriteLine("Collision between {0} and {1}", idx - 1, idx);

foreach (var idx in collisionsOnIndices)
    Console.WriteLine("Collision on {0}", idx);

// RESULTS:
// Collision between 4 and 5
// Collision between 6 and 7
// Collision between 8 and 9
// Collision on 0
// Collision on 6
// Collision on 7

alt text

编辑:

我做了两种不同的方法来区分碰撞的类型(即索引之间或索引之间),但如果你的purpouse只是为了检测是否发生碰撞,请执行以下操作:

var collisionDetected =
Enumerable.Range(0, minus.Length).Any(i =>
{
    if (minus[i] == plus[i])
        return true;
    if (i > 0 &&
        (((minus[i - 1] - plus[i - 1] < 0) && (minus[i] - plus[i] > 0)) ||
        ((minus[i - 1] - plus[i - 1] > 0) && (minus[i] - plus[i] < 0)) ||
        ((minus[i - 1] - plus[i - 1] == 0) && (minus[i] - plus[i] == 0))))
    {
        return true;
    }
    return false;
});

一旦发现碰撞,此代码就会返回,因此上述方法通常会更快。

答案 2 :(得分:3)

一种方法是将每个系列分成线段,然后比较两个系列中的相应(通过索引)段。

由于具体提及LINQ,这是实现这一目标的一种方法。它不是很漂亮:

var minusPairs = minus.Zip(minus.Skip(1), (prev, next) => new { prev, next });
var plusPairs = plus.Zip(plus.Skip(1), (prev, next) => new { prev, next });

var positions = minusPairs.Zip
               (plusPairs, (mPair, pPair) =>
                mPair.prev > pPair.prev 
                     && mPair.next > pPair.next ? "MinusAbove" :
                mPair.prev < pPair.prev
                     && mPair.next < pPair.next ? "PlusAbove" :
               "Intersection");

输出:

MinusAbove
MinusAbove
MinusAbove
Intersection

(请注意,最后一点没有获得PlusAbove,因为它所属的唯一段代表Intersection。如果需要,您可能需要更改此行为。)

说实话,如果你需要做任何事情,我会回避任何“可爱”的解决方案,即使稍微比这更复杂(例如找到交叉点)。这里需要良好的面向对象设计。

答案 3 :(得分:1)

为什么你不能这样做:

for i=1...n
    if minus[i] > plus[i]
         return "Crossed over at index i"

答案 4 :(得分:1)

public string DetermineCollisionInfo(double current, double next)
{
  string currentInfo =
    current == 0.0 ? "Plus and Minus have same value" :
    current < 0.0 && next > 0.0 ? "Intersection occurs" :
    current > 0.0 && next < 0.0 ? "Intersection occurs" :
    "No Intersection";

  string nextInfo =
    next > 0.0 ? "Plus will be on top" :
    next < 0.0 ? "Minus will be on top" :
    "Plus and Minus will have same value";

  return currentInfo + ".  " + nextInfo;
}

然后,后来:

IEnumerable<double> differences = Enumerable
    .Range(0, minus.Length)
    .Select(i => plus[i] - minus[i]);

double current = differences.First();
IEnumerable<string> analysis = differences
  .Skip(1)
  .Select(next =>
  {
    string result = DetermineCollisionInfo(current, next);
    current = next;
    return result;
  });

foreach(string info in analysis)
{
  Console.WriteLine(analysis);
}

答案 5 :(得分:1)

如果minusplus是列表:

var plus1 = plus.Skip(1);
var retVal = minus
    .Skip(1)
    .Select((p,i) => new { index = i, value = (minus[i] > plus[i]) != (p > plus1[i])})
    .Where( p => !p.value);