C# 如何从每个内部列表中提取所需的元素?

C# 如何从每个内部列表中提取所需的元素?,c#,.net,list,linq,dictionary,C#,.net,List,Linq,Dictionary,我有一个存储在列表中的数据,这是一个对象列表 我需要遍历每个内部列表,检查对象是否满足条件,然后将其存储在其他列表中 public class Data //class that actually holds data { public string DataPart; public string Category; public Data (string dataPart, string category) { this.DataPart = d

我有一个存储在列表中的数据,这是一个对象列表

我需要遍历每个内部列表,检查对象是否满足条件,然后将其存储在其他列表中

public class Data //class that actually holds data
{
    public string DataPart;
    public string Category;
    public Data (string dataPart, string category)
    {
        this.DataPart = dataPart;
        this.Category = category;
    }
}
存储数据的数据结构如下所示:

Dictionary<int, List<Data>>
字典
显示我当前解决方案的示例代码:

Dictionary<int, List<Data>> dataTbl = new Dictionary<int, List<Data>>();

//initializing the data structure
List<Data> lst1 = new List<Data>();
lst1.Add(new Data("data1OfLst1", "cat1"));
lst1.Add(new Data("data2OfLst1", "cat2"));
lst1.Add(new Data("data3Oflst1", "cat3"));
dataTbl.Add(1, lst1);
List<Data> lst2 = new List<Data>();
lst2.Add(new Data("data1OfLst2", "cat1"));
lst2.Add(new Data("data2OfLst2", "cat2"));
lst2.Add(new Data("data3Oflst2", "cat3"));
dataTbl.Add(2, lst2);

List<Data> cat1Data = new List<Data>();
foreach(List<Data> datList in dataTbl.Values)
{
    if(datList.Any( x => x.Category == "cat1"))
        cat1Data.Add(datList.Where(x => x.Category == "cat1").FirstOrDefault());
}
Dictionary dataTbl=newdictionary();
//初始化数据结构
List lst1=新列表();
lst1.添加(新数据(“data1OfLst1”、“cat1”);
lst1.添加(新数据(“data2OfLst1”、“cat2”);
lst1.添加(新数据(“数据3OFLST1”、“cat3”);
数据待添加(1,lst1);
List lst2=新列表();
lst2.添加(新数据(“data1OfLst2”、“cat1”);
lst2.添加(新数据(“data2OfLst2”、“cat2”);
lst2.添加(新数据(“数据3OFLST2”、“cat3”);
数据待添加(2,lst2);
List cat1Data=新列表();
foreach(列出dataTbl.Values中的数据列表)
{
if(datList.Any(x=>x.Category==“cat1”))
cat1Data.Add(datList.Where(x=>x.Category==“cat1”).FirstOrDefault();
}
但是字典中的记录数和每个记录的
列表中的元素数将是一个很大的数字。因此,我正在寻找更好的解决方案

请注意,
字典中的某些记录可能不包含满足条件的任何此类数据(此处为
“cat1”
检查)。最终列表不应包含
null

编辑:


一般假设(不是死硬的验证)内部列表中应该只有一个(或没有)特定类别的条目,因此不会有包含多个对象的内部列表,这些对象使用
“cat1”

您可以这样做,并使用
cat1
获取所有记录

var list = dictionary.Values              // To get just the List<Data>s
                     .SelectMany(x => x)  // Flatten
                     .Where(x => x.Category == "cat1")
                     .ToList();           // Listify

对于性能,请尝试并行linq,这将使用多线程,但建议与没有并行性能的情况进行比较并使用它

var list = dictionary.Values.AsParallel() // To get just the List<Data>s
                     .SelectMany(x => x)  // Flatten
                     .Where(x => x.Category == "cat1")
                     .ToList();           // Listify
var list=dictionary.Values.aspallel()//仅获取列表
.SelectMany(x=>x)//展平
.其中(x=>x.类别==“cat1”)
.ToList();//列表化

注意:使用forloop如果你真的关心性能,请删除所有你尝试得更好的linq代码只使用forloop

,正如我在评论中所说的,只要你没有使用分析器来指示如果你甚至有性能问题,如果因此,如果这是由你的代码或其他你想不到的原因造成的,你就不会为更快的代码而烦恼。你看,有很多if

除此之外,我还为您提供了一些更智能的代码,它们不会更快——如果有的话,但更易于阅读,因此也更易于维护,这应该是您的主要目标,其他一切都只是在寻找纳秒

List<Data> cat1Data = new List<Data>();
foreach(List<Data> datList in dataTbl.Values)
{
    var el = datList.FirstOrDefault(x => x.Category == "cat1");
    if(el != null)
        cat1Data.Add(el);
}
List cat1Data=new List();
foreach(列出dataTbl.Values中的数据列表)
{
var el=datList.FirstOrDefault(x=>x.Category==“cat1”);
如果(el!=null)
CAT1数据添加(el);
}
FirstOrDefault
将返回默认值(
null
对于引用类型,对于结构类型,返回结构的默认值)。事实上,你对同一件事检查了两次


因此,您不需要检查当前列表中是否有满足您条件的元素,然后再次选择此元素。相反,直接搜索并添加它(如果找到)。

为什么要在循环中检查两次条件?这就像做同样的事情三次。只需根据条件直接选择列表即可。不需要循环,也不需要第一次检查:

List<Data> cat1Data = dataTbl.Values
                             .SelectMany(x => x)
                             .Where(x => x.Category == "cat1")
                             .ToList();
List cat1Data=dataTbl.Values
.SelectMany(x=>x)
.其中(x=>x.类别==“cat1”)
.ToList();
正如HenkHolterman提到的,它也可以这样写:

List<Data> cat1Data = dataTbl.SelectMany(x => x.Value)
                             .Where(x => x.Category == "cat1")
                             .ToList();
List cat1Data=dataTbl.SelectMany(x=>x.Value)
.其中(x=>x.类别==“cat1”)
.ToList();

结果是相同的,但性能可能会有所不同。

我建议仅当索引除了位置位置之外还有特殊含义时才使用字典。在您的情况下,您可以创建列表对象的列表

 public class MainClass
{
    public int Id { get; set; }
    public List<Data> Data { get; set; }
}
public类MainClass
{
公共int Id{get;set;}
公共列表数据{get;set;}
}
然后将代码替换为

        MainClass dataTbl = new MainClass();
        List<Data> lst1 = new List<Data>();
        lst1.Add(new Data("data1OfLst1", "cat1"));
        lst1.Add(new Data("data2OfLst1", "cat2"));
        lst1.Add(new Data("data3Oflst1", "cat3"));
        dataTbl.Id = 1;
        dataTbl.Data = lst1;

        List<Data> lst2 = new List<Data>();
        lst2.Add(new Data("data1OfLst2", "cat1"));
        lst2.Add(new Data("data2OfLst2", "cat2"));
        lst2.Add(new Data("data3Oflst2", "cat3"));
        dataTbl.Id = 2;
        dataTbl.Data = lst2;

        List<Data> cat1Data = new List<Data>();

        cat1Data = dataTbl.Data.Where(i => i.Category.Contains("cat1")).ToList();
mainclassdatatbl=newmainclass();
List lst1=新列表();
lst1.添加(新数据(“data1OfLst1”、“cat1”);
lst1.添加(新数据(“data2OfLst1”、“cat2”);
lst1.添加(新数据(“数据3OFLST1”、“cat3”);
dataTbl.Id=1;
dataTbl.Data=lst1;
List lst2=新列表();
lst2.添加(新数据(“data1OfLst2”、“cat1”);
lst2.添加(新数据(“data2OfLst2”、“cat2”);
lst2.添加(新数据(“数据3OFLST2”、“cat3”);
dataTbl.Id=2;
dataTbl.Data=lst2;
List cat1Data=新列表();
cat1Data=dataTbl.Data.Where(i=>i.Category.Contains(“cat1”)).ToList();
Contains将确保您的数据类别仅为“cat1”,并且不包含任何空值


如果您遇到任何问题,请务必告诉我。

您可以在不首先展平的情况下查询集合,然后在结尾处删除由
FirstOrDefault
导致的任何空值:

dataTbl.Values
       .Select(x => x.FirstOrDefault(y => y.Category == "cat1"))
       .Where(x=>x != null);

如果您已经有了一个有效的解决方案,您应该转到。然而,你认为什么是“更好”呢?性能方面?记忆方面?代码数量减少?@HimBromBeere性能方面。是的,下一次在这种情况下我会问这个问题。如果考虑性能,你应该使用一个分析器来指出你是否有性能问题,以及这是否是由代码引起的。或者换句话说:如果您考虑的是性能方面的问题,那么for循环在任何时候都比linq查询好,并且可以尝试并行l
dataTbl.Values
       .Select(x => x.FirstOrDefault(y => y.Category == "cat1"))
       .Where(x=>x != null);