Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/316.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 基于1-many配置中的公共字段数据点筛选两个列表的最快方法_C#_Linq_List_Join - Fatal编程技术网

C# 基于1-many配置中的公共字段数据点筛选两个列表的最快方法

C# 基于1-many配置中的公共字段数据点筛选两个列表的最快方法,c#,linq,list,join,C#,Linq,List,Join,这篇文章是关于性能的。我有两个主要的对象列表(在这里,我将使用PEOPLE/PERSON作为替身)。首先,我需要通过First\u Name属性过滤一个列表-然后我需要根据共享日期从每个主列表创建两个过滤列表-一个列表只有一个名称,另一个列表有每个名称,但两个列表都只包含匹配的日期条目(一个列表中没有其他列表中不存在的日期)。我编写了一个伪代码,将问题简化为下面的核心问题。阅读时请理解,生日并不是最佳选择,因为每个人都有多个日期条目。因此,请假设每个人大约有5000个“生日”阅读以下代码时: p

这篇文章是关于性能的。我有两个主要的
对象列表
(在这里,我将使用
PEOPLE/PERSON
作为替身)。首先,我需要通过
First\u Name属性
过滤一个列表
-然后我需要根据共享日期从每个主列表创建两个过滤列表
-一个列表只有一个名称,另一个列表有每个名称,但两个列表都只包含匹配的日期条目(一个列表中没有其他列表中不存在的日期)。我编写了一个
伪代码
,将问题简化为下面的核心问题。阅读时请理解,生日并不是最佳选择,因为每个人都有多个日期条目。因此,请假设每个人大约有5000个“生日”阅读以下代码时:

public class Person
{
    public string first_Name;
    public string last_Name;
    public DateTime birthday;
}
public class filter_People
{
    List<Person> Group_1 = new List<Person>();// filled from DB Table "1982 Graduates" Group_1 contains all names and all dates
    List<Person> Group_2 = new List<Person>();// filled from DB Table "1983 Graduates" Group_2 contains all names and all dates
    public void filter(List<Person> group_One, List<Person> group_Two)
    {
        Group_1 = group_One;
        Group_2 = group_Two;
        //create a list of distinct first names from Group_1
        List<string> distinct_Group_1_Name = Group_1.Select(p => p.first_Name).Distinct().ToList();

        //Compare each first name in Group_1 to EVERY first name in Group 2, using only records with matching birthdays
        Parallel.For(0, distinct_Group_1_Name.Count, dI => {
            //Step 1 - create a list of person out of group_1 that match the first name being iterated
            List<Person> first_Name_List_1 = Group_1.Where(m => m.first_Name == distinct_Group_1_Name[dI]).ToList();
            //first_Name_List_1 now contains a list of everyone named X (Tom). We need to find people from group 2 who match Tom's birthday - regardless of name

            //step 2 - find matching birthdays by JOINing the filtered name list against Group_2  
            DateTime[] merged_Dates = first_Name_List_1.Join(Group_2, d => d.birthday, b => b.birthday, (d, b) => b.birthday).ToArray();
            //Step 3 - create filtered lists where Filtered_Group_1 contains ONLY people named Tom, and Filtered_Group_2 contains people with ANY name sharing Tom's birthday. No duplicates, no missing dates.
            List<Person> Filtered_Group_1 = first_Name_List_1.Where(p => p.birthday.In(merged_Dates)).ToList();
            List<Person> Filtered_Group_2 = Group_2.Where(p => p.birthday.In(merged_Dates)).ToList();
            //Step 4 -- move on adn process the two filtered lists (outside scope of question)
            //each name in Group_1 will then be compared to EVERY name in Group_2 sharing the same birthday
            //compare_Groups(Filtered_Group_1,Filtered_Group_2)

        });
    }
}
public static class Extension
{
    public static bool In<T>(this T source, params T[] list)
    {
        return list.Contains(source);
    }
}
公共类人物
{
公共字符串名称;
公共字符串姓氏;
公众生日;
}
公共类过滤器
{
列表组_1=new List();//从数据库表“1982毕业生”中填写组_1包含所有姓名和日期
列表组_2=new List();//从DB表“1983毕业生”中填写组_2包含所有姓名和日期
公共无效筛选器(列表组\u 1、列表组\u 2)
{
第1组=第1组;
第2组=第2组;
//创建组_1中不同名字的列表
列出不同的组名=组名。选择(p=>p.first\u Name).distinct().ToList();
//仅使用具有匹配生日的记录,将组_1中的每个名字与组2中的每个名字进行比较
Parallel.For(0,distinct_Group_1_Name.Count,dI=>{
//步骤1-创建组_1中与被迭代的名字匹配的人的列表
List first_Name_List_1=Group_1.其中(m=>m.first_Name==distinct_Group_1_Name[dI])。ToList();
//first_Name_List_1现在包含一个名为X(Tom)的所有人的列表。我们需要从第2组中找到与Tom的生日相匹配的人,不管他们叫什么名字
//步骤2-根据组2加入筛选的姓名列表,查找匹配的生日
DateTime[]合并日期=名字列表1.加入(组2,d=>d.生日,b=>b.生日,(d,b)=>b.生日)。ToArray();
//步骤3-创建筛选列表,其中筛选组1只包含名为Tom的人,筛选组2包含名为Tom的人。没有重复,也没有遗漏日期。
List Filtered_Group_1=first_Name_List_1.Where(p=>p.birth.In(merged_Dates)).ToList();
列表过滤的组=组2.Where(p=>p.birth.In(合并的日期)).ToList();
//步骤4——继续adn处理两个过滤列表(超出问题范围)
//然后将组_1中的每个姓名与组_2中共享同一生日的每个姓名进行比较
//比较组(过滤组1、过滤组2)
});
}
}
公共静态类扩展
{
公共静态布尔输入(此T源,参数T[]列表)
{
返回列表。包含(来源);
}
}
这里的想法是从数据库中获取两个不同的主名称列表,并创建日期匹配的子列表(一个仅包含一个名称,另一个包含所有名称)允许基于具有匹配日期索引的相同长度的
数据集进行
一对多比较
。最初的想法是简单地从数据库加载列表,但列表很长,加载所有名称数据并使用
选择/位置/加入
要快得多。我说“快得多”,但这是相对的

我曾尝试使用键将
Group_1
Group_2
转换为字典和匹配日期。改进不大。
Group_1大约有1200万条记录
大约4800个不同的名称
,每个名称有多个日期),而组2也差不多,所以这里的输入是
1200万条
记录,输出是数以百万计的记录。即使我将此方法作为一个单独的任务运行,并将结果排队等待另一个线程处理,但拆分这些列表并保持同步也需要花费很长时间

此外,我意识到使用类Person的代码没有多大意义,但它只是使用伪代码的问题的一个代表。实际上,该方法按日期对多个数据集进行排序,并比较一对多的相关性

对于如何以更高效的方式完成筛选这一对多比较的任何帮助,我们将不胜感激


谢谢!

在当前格式的代码中,我看到太多的问题,使它无法与您提到的数据类型一起面向性能。并行性对于较差的算法数据结构选择来说并不是灵丹妙药

目前,对于每次比较,它都使用
线性搜索O(N)
,因此对于M个操作,它使用
M*O(N)
,即使我们将这些操作
O(logN)
,甚至更好的
O(1)
,执行时间也会大大缩短

不要使用
Distinct
然后使用
Where
子句在
Parallel loop
中搜索,而是使用
GroupBy
对记录进行
aggregate/group
操作,并在相同操作中创建一个字典,以确保使用给定名称轻松搜索记录

var nameGroupList = Group_1.GroupBy(p => p.first_Name).ToDictionary(p => p.Key, p => p);
这将帮助您摆脱原始代码中的以下两个操作(其中一个并行操作是重复操作,这会严重影响性能)

因为在扩展方法中,您每次都以
O(N)
操作的形式运行
列表。包含
,这会降低性能。以下是可能的选项:

将以下操作也从并行循环中取出:

DateTime[] merged_Dates = first_Name_List_1.Join(Group_2, d => d.birthday, b => b.birthday, (d, b) => b.birthday).ToArray();
而是创建另一个类型为的
字典
<
p.birthday.In(merged_Dates)
DateTime[] merged_Dates = first_Name_List_1.Join(Group_2, d => d.birthday, b => b.birthday, (d, b) => b.birthday).ToArray();
personDictionary["PersonCode"].Intersect(Group2,IEqualityComparer(using Date))