将linq与Contains一起使用 - 获取错误

时间:2017-09-23 14:04:11

标签: c# 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”上找到相似的名称。 例如:John Smith和John Smith Jr. 我用.Where子句写了一些内容,但我的语法错误

 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语句中 - “字符串不包含'Field'的定义,并且最好的扩展方法重载'System.Data.DatarowExtensions.Field有一些无效的参数'。

你可以帮我解释一下这段代码吗?或者我可以使用contains找到相似名称的任何其他方式。

2 个答案:

答案 0 :(得分:0)

如果没有发布原始集合的类型,很难说,但问题似乎正是您的错误消息中所述。

LINQ在迭代步骤中工作,在调用Select(dr => dr.Field<string>("MergedName").Replace("'", "''"))后,您的下一个expresion适用于字符串集合。字符串类型

上没有方法.Field

我想您可以尝试将where子句中的C.Field<string>("MergedName").ToLower()简化为C.ToLower()

你也没有在你的第二个语句中进行任何分组,因此Select(g => g.Key)不会工作,因为String类型上也没有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();

只要将自己的条件放入最后一个语句的任何部分,就会有两个字符串mn,可以根据需要进行比较。
这绝对不是您问题的最佳性能解决方案,但它在您的任务中使用LINQ,并且易于编写和理解。

澄清后:

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

此条件基于您问题中的条件,而不是评论中的条件。但你不需要使用这个内联sytax并可以调用一些自定义方法,所以它看起来像.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
        }
    }

这可能会导致问题,因此请确保您的相等函数是对称的(如果a == 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
    }
}

答案 1 :(得分:0)

让我举例告诉你为什么你不应该这样做。正如Noxor所说,一种可行的方法是使用IEqualityComparer。但现在的问题是:什么是平等的?你的&#34;包含平等&#34;引入了一种你无法解决的模糊性。

让我以最基本的方式解释这一点,忘记案例和字符串替换。看到这个小的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

Abby Kelley Foster发生了什么事?

比较者首先遇到了两个第一个不等的行,Abby Kelley算了一个,继续比较Kelley Foster和Abby Kelley Foster:宾果游戏! &#34;等&#34 ;.但是,此时它永远不会返回到第一行以将其与第三行进行比较。

你可以尝试一种比较所有行的更复杂(但仍然很简单)的算法,但是你会得到

Abby Kelley Foster  3

还是错的。只有Abby Kelley和Abby Kelley Foster是同一个人。 Kelley Foster完全是另一个人。换句话说:您无法通过任何自动算法解决此问题。只有精确的等式才能通过简单的算法确定。

用一个人为的例子来打这个家:假设一个条目只是&#34; Jr。&#34;。现在所有的名字都带有&#34; Jr。&#34;将被视为重复!