【问题标题】:Compare Two Ordered Lists in C#在 C# 中比较两个有序列表
【发布时间】:2014-01-09 20:58:41
【问题描述】:

问题是我有两个字符串列表。一个列表是另一个列表的近似值,我需要某种方法来测量近似值的准确性。

作为对近似值进行评分的一种临时方法,在根据与字符串对应的数值进行排序后,我将每个列表(近似值和答案)分为 3 个分区(高、中低)。然后我比较近似值中的所有元素,看看字符串是否存在于正确列表的同一分区中。

我将正确分类的字符串数相加,然后除以字符串总数。我知道这是一种非常粗略的方法来衡量估计的准确性,并希望有更好的替代方案可用。这是一项大型工作的一个非常小的组成部分,并且希望不必重新发明轮子。

编辑: 我想我不够清楚。我不需要两个列表完全相等,我需要某种显示列表相似的度量。例如,我们采用的 High-Medium-Low (H-M-L) 方法表明估计的列表足够相似。这种方法的缺点是,如果估计列表中有一个项目位于“高”括号的底部,而在实际列表中,该项目位于中等集合的顶部,则分数算法无法传递。

可能是除了 H-M-L 方法之外,每个分区的底部 20% 与下一个分区的顶部 20% 或类似的东西进行比较。

感谢大家的帮助!!

【问题讨论】:

  • 发布一些相关代码而不是描述怎么样?连同输入、输出和预期输出
  • 你能发布你的代码吗??
  • 听起来像是一个完整的外连接。差异列表始终是完全外连接。
  • @AnthonyWood 列表的大小是否始终相同?
  • 为什么我的代码是相关的?我要求一个新的算法。列表是字符串,因此解决方案对任何字符串都是通用的。输入来自不同的 csv 文件,这些文件被转换为内存矩阵。输出可能是最准确的分数

标签: c# performance list-comparison


【解决方案1】:

因此,我们采用一系列项目并将其分组为具有高、中和低三个类别的分区。让我们首先创建一个对象来表示这三个分区:

public class Partitions<T>
{
    public IEnumerable<T> High { get; set; }
    public IEnumerable<T> Medium { get; set; }
    public IEnumerable<T> Low { get; set; }
}

接下来要进行估计,我们要获取其中两个对象,一个用于实际对象,一个用于估计值。对于每个优先级,我们想查看两个集合中有多少项;这是一个“十字路口”;我们想总结每个集合的交集的计数。

然后将这个计数除以总数:

public static double EstimateAccuracy<T>(Partitions<T> actual
    , Partitions<T> estimate)
{
    int correctlyCategorized = 
        actual.High.Intersect(estimate.High).Count() +
        actual.Medium.Intersect(estimate.Medium).Count() +
        actual.Low.Intersect(estimate.Low).Count();

    double total = actual.High.Count()+
        actual.Medium.Count()+
        actual.Low.Count();

    return correctlyCategorized / total;
}

当然,如果我们将其概括为不是 3 个优先级,而是一个序列序列,其中每个序列对应于某个桶(即有 N 个桶,而不仅仅是 3 个),那么代码实际上会变得更容易:

public static double EstimateAccuracy<T>(
    IEnumerable<IEnumerable<T>> actual
    , IEnumerable<IEnumerable<T>> estimate)
{
    var query = actual.Zip(estimate, (a, b) => new
    {
        valid = a.Intersect(b).Count(),
        total = a.Count()
    }).ToList();
    return query.Sum(pair => pair.valid) /
        (double)query.Sum(pair => pair.total);
}

【讨论】:

  • @AlbertoMontellano 寻求答案。
  • 我认为你的回答是正确的。但是,解决问题的逻辑与问题使用的逻辑不同吗?他是在要求另一种方式吗?
  • @AlbertoMontellano 我认为您是唯一正确理解我的问题的人。我已经实现了分区可枚举扩展,但是这些对于改进我的实现很有帮助
【解决方案2】:

好问题。好吧,我认为您可以使用以下方法来比较您的列表:

 public double DetermineAccuracyPercentage(int numberOfEqualElements, int yourListsLength)
    {
        return ((double)numberOfEqualElements / (double)yourListsLength) * 100.0; 
    }

返回的数字应该确定两个列表之间存在多少相等。 如果 numberOfEqualElements = yourLists.Length (Count) 所以它们绝对相等。 近似的准确度 = (numberOfEqualElements / yourLists.Length) 1 = 完全相等,0 = 完全不同,0 到 1 之间的值决定相等的程度。在我的样本中是一个百分比。

如果您比较这 2 个列表,您将检索到 75% 的相等性,与 4 个相等元素中的 3 个 (3/4) 相同。

        IList<string> list1 = new List<string>();
        IList<string> list2 = new List<string>();

        list1.Add("Dog");
        list1.Add("Cat");
        list1.Add("Fish");
        list1.Add("Bird");

        list2.Add("Dog");
        list2.Add("Cat");
        list2.Add("Fish");
        list2.Add("Frog");


          int resultOfComparing = list1.Intersect(list2).Count();
        double accuracyPercentage = DetermineAccuracyPercentage(resultOfComparing,   list1.Count); 

希望对你有帮助。

【讨论】:

  • 您的CompareTwoLists 方法可以简单地实现为list1.Intersect(list2).Count();
  • 感谢这个,不是确切的答案,但有些内容对改进我现有的实现很有用!非常感谢。
【解决方案3】:

我会同时使用List&lt;String&gt;s 并将每个元素组合成一个IEnumerable&lt;Boolean&gt;

public IEnumerable<Boolean> Combine<Ta, Tb>(List<Ta> seqA, List<Tb> seqB)
{
  if (seqA.Count != seqB.Count)
    throw new ArgumentException("Lists must be the same size...");

  for (int i = 0; i < seqA.Count; i++)
    yield return seqA[i].Equals(seqB[i]));
}

然后使用Aggregate() 来验证哪些字符串匹配并保持运行总数:

var result = Combine(a, b).Aggregate(0, (acc, t)=> t ? acc + 1 : acc) / a.Count; 

【讨论】:

  • 您假设列表的长度相同。我不认为这是给定的。
  • @usr 根据 OP 的描述......我不知道它还能如何工作。
  • 我不知道 OP 到底描述了什么。我的方法:等待澄清(或关闭)。
  • @usr 我不反对。但我认为我能够从字里行间解读到足以推断出意图。
  • @Andrew 根据上面的评论,列表的长度应该相等。
猜你喜欢
  • 1970-01-01
  • 2015-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多