如何判断列表中哪些对象与另一个相同类型的对象最相似?
本文关键字:对象 另一个 同类型 相似 何判断 判断 列表 | 更新日期: 2023-09-27 17:53:22
我想做的是有一个具有属性的对象集合,并传入一个对象作为查询模板。如何对属性值与相同类型的给定输入对象最相似的对象进行排序或确定优先级?
更多细节:
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"};
我希望这个例子匹配第三项,但是在属性c
是null
或"f"
的情况下,它应该返回第一项和第三项。如果属性c
是"r"
,但b
is
null
或"f"
,它应该返回第二项和第三项,因为它们在c
上匹配。
您基本上必须想出一个公式来确定这两个对象的相似程度。为每个属性选择一个权重,然后使用简单的比较来确定该属性是否应该被视为相同的。可以使用某种类型的模糊匹配,尽管这将更加复杂。
一些简单的可以是:
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;
}
此权重精确匹配最高值,一个对象中的空值略少,并且根本不存在差异。
我已经对大量数据集进行了大量模糊匹配,并且有许多场景需要考虑。你似乎正在接近一个简单或一般的情况,对于那些没有涉及大量数据的情况,某种一般的字符串距离比较似乎是合适的。
如果性能很重要,我最好的建议是"了解你的数据"。按照上面的建议,写你自己的评分。
话虽如此,我们使用Levenshtein距离进行模糊字符串匹配。就两个字符串之间的"距离"而言,它是非特定的,因此它可能适合也可能不适合给定的问题。下面是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];
}