简体   繁体   English

Linq计算集合中列表的差异数

[英]Linq count number of differences in lists in a collection

I want to count the number of differences (or similarities) in lists within a collection.The following code is a for loop which produces the right results, comparing every other record with the first record. 我想计算集合中列表中的差异(或相似性)的数量。以下代码是for循环,它产生正确的结果,将每个其他记录与第一个记录进行比较。 Is there a way to do it better? 有没有办法做得更好? With Linq, perhaps? 或许Linq?

public void Main(){
        _records = new ObservableCollection<Record>();
        _records.Add(new Record { Name = "Correct", Results = new List<string> { "A", "B","C" } , Score="100%"} );
        _records.Add(new Record { Name = "John", Results = new List<string> { "A", "B" ,"C" } } ); //Expect score to be 3/3  (100%)
        _records.Add(new Record { Name = "Joseph", Results = new List<string> { "A", "C","B" } }); //Expect score to be 2/3 (67%)
        _records.Add(new Record { Name = "James", Results = new List<string> { "C", "C", "C" } }); //Expect score to be 1/3 (33%)

        for(int i = 1; i < _records.Count(); i++) // Each Results in the _records except "Correct"
        {
            float score = _records[0].Results.Count();
            _records[i].Score = string.Format("{0:p1}", (score - CountDifferences(_records[i].Results, _records[0].Results) )  / score );
        }


}

private int CountDifferences(List<string> x, List<string> y)
{
    return (x.Zip(y, (a, b) => a.Equals(b) ? 0 : 1).Sum());
}

I would go about doing it like this: 我会这样做:

var results =
    from r0 in _records.Take(1)
    from r in _records
    let score = (double)r0.Results.Count()
    let differences = CountDifferences(r.Results, r0.Results)
    select new { record = r, score = ((score - differences) / score).ToString("p1") };

foreach (var result in results)
{
    result.record.Score = result.score;
}

I would, hovever suggest that you do not have .Score as a property of Record as a score is only valid when you can compare one record against another. 我想,霍夫表示你没有.Score作为Record的属性作为分数只有当你可以比较一个记录与另一个记录时才有效。 That would mean that if you have three separate results the score could be different if you compare against either of the other two. 这意味着如果您有三个单独的结果,如果您与其他两个中的任何一个进行比较,那么得分可能会有所不同。

So I would suggest this: 所以我建议这样做:

public class Record
{
    public string Name;
    public List<string> Results;
    public double GetScore(Record benchmark)
    {
        var max = benchmark.Results.Count;
        var differences = benchmark.Results
            .Zip(this.Results, (a, b) => a == b)
            .Where(r => r == false)
            .Count();
        return ((double)max - differences) / max;
    }
}

Then just do this query to get the results: 然后只需执行此查询即可获得结果:

var results =
    from r0 in _records.Take(1)
    from r in _records
    select new
    {
        record = r,
        score = r.GetScore(r0).ToString("p1")
    };

That gives me: 这给了我:

结果

I made the LINQ (with lambda expressions) statement work off a dictionary that uses the students' name as the key and custom class Record as the value. 我将LINQ(带有lambda表达式)语句用于使用学生名称作为键并使用自定义类Record作为值的字典。 Then compare that against a separate List the grades are expected to be. 然后将其与单独的列表进行比较,预期成绩。

List<string> expected = new List<string>(){"A", "B","C" };
Dictionary<string, Record> _records = new Dictionary<string, Record>();
_records["John"] = new Record { Name = "John", Results = new List<string> { "A", "B" ,"C" } } ;
_records["Joseph"]= new Record { Name = "Joseph", Results = new List<string> { "A", "C","B" } } ;
_records["James"] = new Record { Name = "James", Results = new List<string> { "C", "C", "C" } } ;

foreach(var v in _records){
    decimal count = v.Value.Results.Where((x,index) => expected[index]==x).Count()/(decimal)expected.Count();
    v.Value.Score = String.Format("{0:P0}",count);
}

foreach(var v in _records)
    Console.WriteLine("{0} {1}",v.Value.Name,v.Value.Score);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM