假设我在列表中有元素(X,Y和Z),我有一个函数,它生成一个百分比,两个对象彼此相似的程度。
我想要做的是使用我的compareElements对Y和Z运行X,所以:
compareElements(X,Y); // equals 55
compareElements(X,Z); // equals 60
然后Y对抗X和Z
compareElements(Y,X); // equals 55
compareElements(Y,Z); // equals 62
然后Z对Y和X
compareElements(Z,X); // equals 60
compareElements(Z,Y); // equals 62
然后,我返回最高值,即62。
显然,那里有一些重复,我不需要重复,但我不知道如何消除它。
如何构建我的LINQ查询或函数/算法来对每个元素进行此比较,而不重复?
如果可以的话,我更喜欢使用LINQ,因为我传递了一个可枚举的函数,并且在列表实际枚举之前函数返回,因此我们可以节省执行比较的成本,直到枚举列表为止。
我需要的只是比较函数的最高值,62。
注意:我的实际结果集我正在使用列表中3到10个元素之间的平均值,需要通过此比较函数运行。
答案 0 :(得分:8)
我倾向于这样做:
int count = list.Count;
var query = from index1 in Enumerable.Range(0, count)
from index2 in Enumerable.Range(index1 + 1, count - (index1 + 1))
select ComputeSimilarity(list[index1], list[index2]);
var maxSimilarity = query.Max();
答案 1 :(得分:5)
我不确定我是否正确理解你,但尝试这样的事情:
public int compareElementList(List<Element> elements)
{
int result = 0;
for (int i = 0; i < elements.Count - 1; i++)
{
for (int q = i + 1; q < elements.Count; q++)
{
result = Math.Max(result, compareElements(elements[i], elements[q]));
}
}
return result;
}
这将消除您的重复比较。它不使用LINQ,但我认为它仍然具有可读性。
UPDATE :这是我修改的版本来处理IEnumerables。它与Jon Hanna的不同之处在于它不会创建新的List,它只跟踪两个迭代器。
public int compareElementEnumerable(IEnumerable<Element> elements)
{
int result = 0, i = 0, q = 1;
foreach (Element el in elements)
{
foreach (Element el2 in elements)
{
if (q > i)
{
result = Math.Max(result, compareElements(el, el2));
}
q++;
}
i++;
}
return result;
}
答案 2 :(得分:2)
您可以将要测试的可能组合的列表编译为List<Tuple<int, int>>
然后选择最大值
mylist.Select(i => new [] { Tuple.New(i.X, i.Y}, Tuple.New(i.X, i.Z), Tuple.New(i.Y, i.Z)})
.Max(t => compareElements(t.First, t.Second))
答案 3 :(得分:2)
不知道这是不是你要搜索的内容,但我会尝试以这种方式使用LINQ:
var linq = from el1 in list
from el2 in list
where el1 != el2
select CompareFunction(el1, el2);
int max = linq.Max();
比较示例实施:
int CompareFunction(string a, string b)
{
return a.Length - b.Length;
}
通过这种方式,您可以将每个元素与列表中的其他元素进行比较(我认为这是一种排列),除了它本身,然后选择比较值,最后选择最高值。
答案 4 :(得分:2)
为了便于阅读,我会写一个迭代器块来以非重复的方式生成比较:
IEnumerable<Tuple<T, T>> GetComparisons<T>(IEnumerable<T> elements)
{
var visited = new List<T>();
foreach(T current in elements)
{
foreach(T previous in visited)
yield return new Tuple<T, T>(current, previous);
visited.Add(current);
}
}
然后您可以执行以下操作:
var highScore = GetComparisons(listOfElements)
.Select(x=>compareElements(x.Item1, x.Item2)
.Max();
(也就是说,我更喜欢Smelch的建议,因为没有实际理由使用LINQ或迭代器,例如需要可组合的例程。)
答案 5 :(得分:1)
与给定的几个相同,但不需要首先分配给列表。
List<Element> soFar = new List<Element>();
// If I expected a good few duplicate values, and if
// compareElements(x, x) isn't 100% - i.e. it's not a similarity
// check for example, then I'd use HashSet<Element> and skip
// when .Add() fails.
int result = 0;
foreach(Element el in sourceEnumeration)
{
for(int i = 0; i != soFar.Count; ++i)
{
int cmp = compareElements(el, soFar[i]);
if(cmp > result)
{
if(cmp == 100)
return 100;
cmp = result;
}
}
soFar.Add(el);
}
return result;
答案 6 :(得分:0)
一个不可读的LINQ实现(可能无法编译,我还没有测试过):
Enumerable.Range(0, listOfElements.Length).ToList().ForEach(i=>Enumerable.Range(i, listOfElements.Length-i-1).ToList().ForEach(j=>compareElements(listOfElements[i], listOfElements[j]))).Max();