如何判断列表中的哪些对象与同一类型的另一个对象最相似?

时间:2011-04-26 23:17:35

标签: c#

我想要做的是拥有一组具有属性的对象,并传入一个对象作为查询模板。如何对属性值与同一类型的给定输入对象具有最大共同点的对象进行排序或优先级排序?

更多详情:

        List<A> myList = new List<A>() {new A() {b="x"},
                                        new A() {c="r"},
                                        new A() {b="x",c="r"},};

        var myTemplate = new A() {b = "x", c="r"};

我希望此示例与第三项匹配,但在属性cnull"f"的情况下,它应返回第一项和第三项。如果属性c"r",但b is null"f",则应返回第二项和第三项,因为它们匹配c

2 个答案:

答案 0 :(得分:1)

你基本上必须想出一个公式来确定这两个对象的相似程度。为每个属性选择一个权重,然后使用简单的比较来说明该属性是否应该被计为相同。可以使用某种类型的模糊匹配,但这会更复杂。

简单的事情可能是:

public byte Similarity(SomeType other)
{
    byte similarity = 0;
    if (this.Property1 == other.Property1)
        similarity += 25;
    if (this.Property2 == other.Property2)
        similarity += 13;
    if (this.Property3 == other.Property3)
        similarity += 12;
    if (SomeFuzzyComparisonReturnsVerySimilar(this.Property4, other.Property4))
        similarity += 50;
    return similarity;
}

这是一个简单的方法,我定义为从0到100返回一个数字; 100是相同的,0是完全不同的。

一旦掌握了这一点,选择相似的项目就足以让你考虑是一件相当简单的事情;例如:

var similarObjects = ListOfSomeTypes.Where(s => s.Similarity(templateObject) > 75);

或者对它们进行排序:

var sortedBySimilarity = ListOfSomeTypes.OrderByDescending(s => s.Similarity(templateObject));

最终,虽然我的观点是你必须提出自己的“最常见的”定义,但是一旦你有了,那么剩下的可能就很容易了。不是那样想出来就一定很容易。

根据您的问题中的其他详细信息,可能的公式为:

public byte Similarity(A other)
{
    byte similarity = 0;
    if (this.b == null | other.b == null)
        similarity += 25;
    else if (this.b == other.b)
        similarity += 50;
    if (this.c == null | other.c == null)
        similarity += 25;
    else if (this.c == other.c)
        similarity += 50;
    return similarity;
}

此权重与一个对象中的最高值,空值略微匹配,差异完全没有。

答案 1 :(得分:0)

我在庞大的数据集上做了大量的模糊匹配,并且有很多场景需要考虑。您似乎正在接近一个简单或通用的案例,对于那些没有大量数据的情况,某些一般的字符串距离比较似乎是合适的。

如果表现很重要,我最好的建议是“了解你的数据”。如上所述,写下你自己的得分。

话虽如此,我们使用Levenshtein distance进行模糊字符串匹配。就两个弦之间的“距离”而言,它是非常不具体的,因此它可能适合或不适合于给定的问题。这是C#中算法的快速复制/粘贴。它非常容易移植到大多数语言。这将在null输入上抛出异常,因此请务必根据需要添加自己的特殊情况处理。

public static int LevenshteinDistance(string s, string t)
{
    var sLen = s.Length;
    var tLen = t.Length;

    var d = new int[sLen + 1, tLen + 1];

    for (var i = 0; i <= sLen; d[i, 0] = i++) { }
    for (var j = 0; j <= tLen; d[0, j] = j++) { }

    for (var i = 1; i <= sLen; i++)
    {
        for (var j = 1; j <= tLen; j++)
        {
            var cost = (t[j - 1] == s[i - 1]) ? 0 : 1;
            d[i, j] = Math.Min(
                Math.Min(d[i - 1, j] + 1,   // a deletion
                d[i, j - 1] + 1),           // an insertion
                d[i - 1, j - 1] + cost);    // a substitution
        }
    }

    return d[sLen, tLen];
}