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

时间:2018-04-19 06:31:08

标签: c# .net list linq dictionary

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

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

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());
}

但是,词典中的记录数量和每个记录List中的元素数量都是一个很大的数字。因此,我正在寻找更好的解决方案。

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

编辑:

一般假设(不是顽固的验证)内部列表中应该只有一个(或没有)特定类别的条目,因此不会有包含多个{{1的对象的内部列表}}

5 个答案:

答案 0 :(得分:3)

正如我在评论中已经说过的那样,只要您没有使用分析器指示如果您甚至遇到性能问题,那么您就不会为更快的代码而烦恼strong> if so, if 这是由您的代码或其他您不想到的代码引起的。你看:有很多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);
}

FirstOrDefault将返回默认值(null表示引用类型,结构类型表示结构默认值)。实际上你是两次检查同一件事。

因此,您无需检查当前列表中是否存在满足条件的元素,然后再次选择此元素。而是直接搜索它并在找到时添加它。

答案 1 :(得分:2)

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

 public class MainClass
{
    public int Id { get; set; }
    public List<Data> Data { 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();

包含将确保您的类别数据仅为“cat1”,并且不包含任何空值。

如果您遇到任何问题,请尝试告诉我。

答案 2 :(得分:1)

您可以这样做,并使用cat1

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

var list = dictionary.SelectMany(x => x.Value)  // 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

注意:如果您真的关心性能,请使用For循环,删除您尝试过的所有linq代码,只使用forloop

答案 3 :(得分:1)

您可以先查询集合而不进行展平,然后删除最后由FirstOrDefault引起的任何空值:

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

答案 4 :(得分:0)

为什么要在循环内检查两次条件?这就像做同样的事情3次。只需根据条件直接选择您的列表即可。无需循环,无需先进行检查:

List<Data> cat1Data = dataTbl.Values
                             .SelectMany(x => x)
                             .Where(x => x.Category == "cat1")
                             .ToList();

正如HenkHolterman所说,它也可以这样写:

List<Data> cat1Data = dataTbl.SelectMany(x => x.Value)
                             .Where(x => x.Category == "cat1")
                             .ToList();

结果相同,但性能可能略有不同。