私はポイントのリストを持っています (リスト)
- 7,43
- 7,42
- 6,42
- 5,42
- 6,43
- 5,43
linq 式を使用して、0,0 に最も近い点を取得したいと考えています。たとえば、このリストでは 5,42 の値が必要です。
LINQで0,0ポイントに最も近いポイントを見つける方法は?
L^2
以下は、リスト全体の高価な並べ替えを実行せずに、最低のノルム (2 次元での「距離」の最も一般的な定義) を持つポイントを見つけます。
var closestToOrigin = points
.Select(p => new { Point = p, Distance2 = p.X * p.X + p.Y * p.Y })
.Aggregate((p1, p2) => p1.Distance2 < p2.Distance2 ? p1 : p2)
.Point;
これを試して:
List<Point> points = new List<Point>();
// populate list
var p = points.OrderBy(p => p.X * p.X + p.Y * p.Y).First();
またはより高速なソリューション:
var p = points.Aggregate(
(minPoint, next) =>
(minPoint.X * minPoint.X + minPoint.Y * minPoint.Y)
< (next.X * next.X + next.Y * next.Y) ? minPoint : next);
別の方法として、標準ライブラリに IEnumerable.MinBy() および IEnumerable.MaxBy() の実装を追加することを検討してください。
それが利用できる場合、コードは単純になります。
var result = points.MinBy( p => p.X*p.X + p.Y*p.Y );
Jon Skeet は、MinBy と MaxBy の適切な実装を提供しました。
彼はここでそれについて話します: LINQ を使用して最小または最大のプロパティ値を持つオブジェクトを選択する方法
ただし、そこからのリンクは古くなっています。最新バージョンはここにあります:
http://code.google.com/p/morelinq/source/browse/MoreLinq/MinBy.cs
http://code.google.com/p/morelinq/source/browse/MoreLinq/MaxBy.cs
これが完全なサンプルです。明らかに、これはナッツを割る大ハンマーですが、これらのメソッドは標準ライブラリに含めるのに十分役立つと思います。
using System;
using System.Collections.Generic;
using System.Drawing;
namespace Demo
{
public static class EnumerableExt
{
public static TSource MinBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> selector, IComparer<TKey> comparer)
{
using (IEnumerator<TSource> sourceIterator = source.GetEnumerator())
{
if (!sourceIterator.MoveNext())
{
throw new InvalidOperationException("Sequence was empty");
}
TSource min = sourceIterator.Current;
TKey minKey = selector(min);
while (sourceIterator.MoveNext())
{
TSource candidate = sourceIterator.Current;
TKey candidateProjected = selector(candidate);
if (comparer.Compare(candidateProjected, minKey) < 0)
{
min = candidate;
minKey = candidateProjected;
}
}
return min;
}
}
public static TSource MinBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> selector)
{
return source.MinBy(selector, Comparer<TKey>.Default);
}
}
public static class Program
{
static void Main(string[] args)
{
List<Point> points = new List<Point>
{
new Point(7, 43),
new Point(7, 42),
new Point(6, 42),
new Point(5, 42),
new Point(6, 43),
new Point(5, 43)
};
var result = points.MinBy( p => p.X*p.X + p.Y*p.Y );
Console.WriteLine(result);
}
}
}
ローリングのソリューションは間違いなく短いですが、ここに別の方法があります
// project every element to get a map between it and the square of the distance
var map = pointsList
.Select(p => new { Point = p, Distance = p.x * p.x + p.y * p.y });
var closestPoint = map // get the list of points with the min distance
.Where(m => m.Distance == map.Min(t => t.Distance))
.First() // get the first item in that list (guaranteed to exist)
.Point; // take the point
への最短距離を持つすべての要素を見つける必要がある場合は0,0
、単純に削除First
して aを実行しSelect(p => p.Point)
、(マッピングとは対照的に) ポイントを取得します。