如何找到包含最接近属性值的对象的List索引?
示例,类MyData包含属性Position。 class MyDataHandler有一个MyData列表,位置为:1,3,14,15,22。
MyDataHandler有一个名为GetClosestIndexAt的方法,如果输入值为13,则该方法必须返回索引2.
示例代码:
public class MyData
{
public double Position { get; set; }
public string Name { get; set; }
}
public class MyDataHandler
{
private List<MyData> myDataList = new List<MyData>();
public MyDataHandler()
{
FillMyData(myDataList);
}
public int GetClosestIndexAt(double position)
{
int index = -1;
//How to get the index of the closest MyDataList.Position to position value.
//index = ?????
return index;
}
private void FillMyData(List<MyData> MyDataList)
{
//fill the data...
}
}
答案 0 :(得分:2)
您可以使用LINQ执行此操作,如下所示:
var res = myDataList
.Select((v, i) => new {Position = v.Position, Index = i}) // Pair up the position and the index
.OrderBy(p => Math.Abs(p.Position - position)) // Order by the distance
.First().Index; // Grab the index of the first item
这个想法是将位置与列表中的索引配对,按特定位置的距离排序,抓取第一个项目,并获得其索引。
当myDataList
中没有单独的元素时,您需要处理这种情况。这是demo on ideone。
答案 1 :(得分:1)
使用重载的Enumerable.Select方法,通过合并元素的索引将序列的每个元素投影到新的表单中:
myDataList.Select((d,i) => new { Position = d.Position, Index = i })
.OrderBy(x => Math.Abs(x.Position - position))
.Select(x => x.Index)
.DefaultIfEmpty(-1) // return -1 if there is no data in myDataList
.First();
使用MoreLinq的MinBy运算符(可从NuGet获得)的更好解决方案:
public int GetClosestIndexAt(double position)
{
if (!myDataList.Any())
return -1;
return myDataList.Select((d,i) => new { Position = d.Position, Index = i })
.MinBy(x => Math.Abs(x.Position - position))
.Index;
}
如果您不想使用库,可以创建自己的MinBy扩展名:
public static TSource MinBy<TSource, TKey>(
this IEnumerable<TSource> source, Func<TSource, TKey> selector)
{
using (IEnumerator<TSource> sourceIterator = source.GetEnumerator())
{
if (!sourceIterator.MoveNext())
throw new InvalidOperationException("Empty sequence");
var comparer = Comparer<TKey>.Default;
TSource min = sourceIterator.Current;
TKey minKey = selector(min);
while (sourceIterator.MoveNext())
{
TSource current = sourceIterator.Current;
TKey currentKey = selector(current);
if (comparer.Compare(currentKey, minKey) >= 0)
continue;
min = current;
minKey = currentKey;
}
return min;
}
}
答案 2 :(得分:1)
正如我在评论中所说,我认为最有效的方法是避免对整个数据进行不必要的排序,以获得第一个元素。我们可以通过搜索具有最小差异的元素来选择它,单独计算。它需要两次列表迭代但不需要排序。给出:
var myDataList = new List<MyData>()
{
new MyData() { Name = "Name1", Position = 1.0 },
new MyData() { Name = "Name3", Position = 3.0 },
new MyData() { Name = "Name14", Position = 14.0 },
new MyData() { Name = "Name15", Position = 15.0 },
new MyData() { Name = "Name22", Position = 22.0 },
};
double position = 13.0;
你可以写:
var result =
myDataList.Select((md, index) => new
{
Index = index,
Diff = Math.Abs(md.Position - position)
})
.Where(a => a.Diff == myDataList.Min(md => Math.Abs(md.Position - position)))
.First()
.Index;