如何在C#中实现比较功能

发布于 2024-12-22 09:10:13 字数 715 浏览 0 评论 0 原文

假设我在列表中有元素(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 个元素之间的平均值,需要通过此比较函数运行这些平均值。< /em>

Say I have elements (X, Y, and Z) in a list, I have a function, that generates a percentage, of how much two objects resemble each other.

What I want to do, is run X against Y and Z using my compareElements, so:

compareElements(X,Y); // equals 55
compareElements(X,Z); // equals 60

Then Y against X and Z

compareElements(Y,X); // equals 55
compareElements(Y,Z); // equals 62

Then Z against Y and X

compareElements(Z,X); // equals 60
compareElements(Z,Y); // equals 62

Then, I return the highest value, which is 62.

Obviously, there's some repetition there, I don't need the repetition, but I'm not sure how to eliminate it.

How do I structure my LINQ query, or a function/algorithm to do this comparison on every element, without the repetition?

I'd prefer to use LINQ if I can, as I'm being passed an enumerable and the function returns before the list is actually enumerated, so we can save the cost of performing the compare, until the list is enumerated.

All I need is that highest value, of the compare functions, 62.

Note: My actual result set I'm working with averages between 3 and 10 elements in the list, that need to be ran through this compare function.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

扛起拖把扫天下 2024-12-29 09:10:13

我倾向于这样做:

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();

I'd be inclined to do it like this:

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();
你对谁都笑 2024-12-29 09:10:13

我不确定我是否正确理解你,但尝试这样的事情:

    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,但我认为它仍然具有很好的可读性。

更新:这是我修改后的版本以处理 IEnumerables。它与 Jon Hanna 的不同之处在于它不创建新列表,而只是跟踪两个迭代器。

    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;
    }

I'm not sure I'm understanding you correctly, but try something like this:

    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;
    }

This will eliminate the duplicate comparisons for you. It doesn't use LINQ, but I think it's still pretty readable.

UPDATE: Here is my version modified to handle IEnumerables. It varies from Jon Hanna's in that it doesn't create a new List, it just keeps track of two iterators.

    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;
    }
傾城如夢未必闌珊 2024-12-29 09:10:13

为了便于阅读,我会编写一个迭代器块以非重复的方式生成比较:

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();

这就是说,对于没有实际理由使用 LINQ 或迭代器的情况,我更喜欢 Smelch 的建议,例如需要可组合例程。)

For the sake of readability, I would write an iterator block to generate the comparisons in a non-repetitive manner:

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);
    }
}

Then you can do the following:

var highScore = GetComparisons(listOfElements)
                    .Select(x=>compareElements(x.Item1, x.Item2)
                    .Max();

(That said I prefer Smelch's suggestion for situations where there's no practical reason to use LINQ or iterators, such as having a need for composable routines.)

青芜 2024-12-29 09:10:13

不知道这是否是您要搜索的内容,但我会尝试以这种方式使用 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;
}

通过这种方式,您可以将每个元素与列表中的其他元素进行比较(我认为这是一种排列) )除自身外,然后选择比较值,最后选择最高值。

Don't know if it is what you are searching for, but I would try to use LINQ in this way:

var linq = from el1 in list
           from el2 in list
           where el1 != el2
           select CompareFunction(el1, el2);

int max = linq.Max();

Comparison sample implementation:

int CompareFunction(string a, string b)
{
    return a.Length - b.Length;
}

This way you compare each element against the other elements in the list (it is a sort of permutation I think) except itself, then select the comparison value and finally the highest value.

玩套路吗 2024-12-29 09:10:13

您可以将要测试的可能组合列表编译为 List>
然后选择最大值

 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))

You could compile a list of the possible combinations you want to test into a List<Tuple<int, int>>
and then select the maximum

 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))
季末如歌 2024-12-29 09:10:13

与给出的一对几乎相同,但不需要首先分配给列表。

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;

Pretty much the same as a couple given, but doesn't require one to assign to a list first.

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;
锦爱 2024-12-29 09:10:13

不可读的 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();

An unreadable LINQ implementation (may not compile, I haven't tested):

Enumerable.Range(0, listOfElements.Length).ToList().ForEach(i=>Enumerable.Range(i, listOfElements.Length-i-1).ToList().ForEach(j=>compareElements(listOfElements[i], listOfElements[j]))).Max();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文