使用LINQ与包含 - 获取错误
我是Linq的新手,仍然试图熟悉它。我有以下LINQ查询找到重复和它完美的作品象下面这样:使用LINQ与包含 - 获取错误
//“MergedName”是数据列,我查询,并找到重复的名称。
var duplicates = result.AsEnumerable()
`.Select(dr => dr.Field<string("MergedName").Replace("'", "''"))
.GroupBy(x => x)
.Where(g => g.Count() > 1)
.Select(g => g.Key)
.ToList();
foreach (string duplicate in duplicates.ToArray())
{
// Logic to keep one and delete another duplicate.
}
现在,我想要在同一列“MergedName”上找到类似名称。 对于如:约翰·史密斯和约翰·史密斯小 我写的东西用。凡条款,但事情是错我的语法
var duplicates = result.AsEnumerable()
.Select(dr => dr.Field<string>("MergedName").Replace("'", "''"))
.Where(C => C.Field<string>("MergedName").ToLower().IndexOf(C.Field<string>("MergedName").ToLower().Trim()) != 1)
.Select(g => g.Key)
.ToList();
foreach (string duplicate in duplicates.ToArray())
{
// Logic to keep one and delete another duplicate.
}
错误:WHERE语句 - “字符串不包含定义‘现场’和最佳推广方法重载“System.Data.DatarowExtensions.Field有一些无效的参数”。
能否请你帮我这个代码吗?或任何其他方式在那里我可以使用包含找到相似的名称。
没有你张贴原始集合的类型很难说,但问题似乎正是你的错误信息所述。
LINQ工作在迭代步骤,并呼吁Select(dr => dr.Field<string>("MergedName").Replace("'", "''"))
后,你接下来expresion适用于字符串的集合。还有在字符串类型,没有方法.Field
我想你可以试试你的where子句中简化C.Field<string>("MergedName").ToLower()
到C.ToLower()
您还没有做任何分组在你的第二个语句,以便Select(g => g.Key)
不会工作,因为没有字符串类型的关键属性。
这只能解决语法问题,Where子句仍然看起来很奇怪。你正在比较每个字符串本身。
你可以尝试像
var names = result.AsEnumerable()
.Select(dr => dr.Field<string("MergedName").Replace("'", "''").ToLower().Trim())
.ToList(); //ToList not necessary here, but could prevent multiple executions of the expresion
var duplicates = names.Where(n => names.Any(m => n.IndexOf(m) != -1)) //quadratic complexity
.ToList();
只要把自己的状态进入最后陈述的任何部分,你有两个字符串m
和n
那里,但是你希望可以对它们进行比较。
这绝对不是您问题的最佳解决方案,但它使用LINQ,因为它在您的questinon中很容易编写和理解。
澄清后:
var enumerableResult = result.AsEnumerable();
var duplicates = enumerableResult.
.Where(dr => enumerableResult.Any(dr2 => /*your comparison*/)
.ToList();
比较可能是这样的:
dr.Field<string>("MergedName").Replace("'", "''").Trim().ToLower().IndexOf(dr2.Field<string>("MergedName").Replace("'", "''").Trim().ToLower()) != -1
这个条件是根据一个在你的问题,而不是一个在您的评论。但是,你不需要使用内联和语法时才可以调用一些自定义的方法,所以它看起来像.Any(dr2 => AreSamePerson(dr, dr2))
这有再次二次复杂性,问题只有当你有很多的记录进行比较。
现在,您可以获取人物对象的集合,而不仅仅是字符串。请记住,你不能从原始的集合中删除重复集合的成员,但需要一些相当复杂的逻辑。
所以最好的解决办法似乎是:
var duplicates = result.AsEnumerable()
.GroupBy(x => x, new PersonyComparer())
.Where(g => g.Count() > 1)
class PersonyComparer : IEqualityComparer<Person>//person is the type of objects that are in starting collection
{
public bool Equals(Person b1, Person b2)
{
if (b2 == null && b1 == null)
return true;
else if (b1 == null | b2 == null)
return false;
if(/*your condition*/)
return true;
else
return false;
}
public int GetHashCode(Person bx)
{
return 0; //you must make sure that objects that are equal have same hashcode
}
}
这可能会导致问题,所以请确保您的相等功能是对称的(如果== b则b == a)和传递(如果a == b和b == c然后a == c)。否则你的团队可能会被搞砸。
然后你就可以在重复征收的对象
foreach(var pgroup in duplicates)
{
foreach(var person in pgroup .Skip(1))
{
//remove from original collection
}
}
让我举例告诉你为什么你不应该想这个迭代。正如Noxor正确指出的那样,一种可行的方法是使用IEqualityComparer
。但现在的问题是:什么是平等的?你的“包含平等”引入你无法解决的模糊性。
让我在最基本的方式解释这一点,忘记的情况下和字符串替换。看到这个小小的Linqpad程序:
void Main()
{
var dt = new DataTable();
dt.Columns.Add("MergedName", typeof(string));
dt.Rows.Add("Abby Kelley Foster");
dt.Rows.Add("Kelley Foster");
dt.Rows.Add("Abby Kelley");
dt.AsEnumerable()
.Select(r => r.Field<string>("MergedName"))
.GroupBy(s => s, new SubstringComparer())
.Select(g => new { g.Key, Count = g.Count() })
.Dump();
}
public class SubstringComparer : IEqualityComparer<string>
{
public bool Equals(string left, string right)
{
return left.Contains(right) || right.Contains(left);
}
public int GetHashCode(string value)
{
return 0; // Just return 0; There is no hashing mechanism implemented that gives "Abby Kelley Foster" and "Abby Kelley" the same hashcode.
}
}
什么是输出?右:
Abby Kelley Foster 3
但现在让我们来改变数据行的顺序:
dt.Rows.Add("Abby Kelley");
dt.Rows.Add("Kelley Foster");
dt.Rows.Add("Abby Kelley Foster");
可以抵扣的输出?这里是:
Abby Kelley 1
Kelley Foster 2
的比较器第一次遇到这两个第一个不平等行,计1阿比·凯利和继续比较凯利福斯特和阿比·凯利福斯特:宾果! “等于”。但是,在这一点上,它永远不会返回到第一行来比较它与第三行。
你可以尝试更复杂(但依然简单)的算法,比较所有的行,但你会得到
Abby Kelley Foster 3
仍然是错误的。只有艾比凯利和艾比凯利福斯特是同一个人。凯利福斯特完全是别人。换句话说:您无法通过任何自动算法解决此问题。只有精确的相等才能通过简单的算法来确定。
为了打这个家有一个人为的例子:假设一个项目是什么,但“小”。现在所有名称都带有“Jr.”将被视为重复!
格特阿诺德 - 同意。您提供的示例是我在数据中遇到和想到的示例。 –
好的,你可能已经想到了,但对我来说唯一的结论就是你不能这样下去。我还没有提到第一个输出(3)在逻辑上不正确的事实,因为它包含两个名字,如果没有第三个名字,那么它们就不会被分组。 –
Noxor - 感谢您对以上解决方案,它可以帮助在正确的方向。我有两个名字,这两个名字在集合中是同一个人:“John Mat Smith”,另一个记录是“John Matthew Smith”,我知道他们是同一个人,所以想删除其中的一个。这就是原因,我正在寻找使用Contains而不是Any.Referred to this link:“https://*.com/questions/23526773/what-is-the-difference-between-contains-and-any-in- LINQ”。有没有办法我可以先查询相似的名字并将它们放入列表中?对于之前没有澄清这一点抱有歉意。 –
我猜包含使用相同方法的对象,所以你可以重写,所以具有类似名称的对象将返回true。然而,这似乎是一个非常糟糕的主意。如果您想从原始集合中删除“重复”记录,请尝试保留重复对象的集合,而不是仅收集字符串。看到我的答案编辑。 – Noxor
你怎么知道他们是同一个人。如果你有其他一些财产,比如社会安全号码,最好用它来代替名字。 – Noxor