Lookup的概念
Lookup 类似于 Dictionary,但把键映射到一个值集上 (通俗讲法就是一个键对应多个值)
这个类在程序集System.Core中实现,用System.Linq命名空间定义。
它不能像一般的字典那样创建,而必须调用方法ToLookup()。
Lookup和IGrouping有点类似但又有点区别。
示例
首先建一个产品类:有ID、类别、价格
internal class Product
{
public int id { get; set; }
public string category { get; set; }
public double value { get; set; }
public override string ToString()
{
return string.Format("[{0}: {1} - {2}]", id, category, value);
}
}
接着定义一个获得产品集的方法,当然,你也可以查询数据库来获取数据
public static List<Product> GetList()
{
var products = new List<Product>
{
new Product {id = 1, category = "Electronics", value = 15.0},
new Product {id = 2, category = "Groceries", value = 40.0},
new Product {id = 3, category = "Garden", value = 210.3},
new Product {id = 4, category = "Pets", value = 2.1},
new Product {id = 5, category = "Electronics", value = 19.95},
new Product {id = 6, category = "Pets", value = 21.25},
new Product {id = 7, category = "Pets", value = 5.50},
new Product {id = 8, category = "Garden", value = 13.0},
new Product {id = 9, category = "Automotive", value = 10.0},
new Product {id = 10, category = "Electronics", value = 250.0},
};
return products;
}
先使用List的GroupBy方法根据产品类别对产品进行分组
static void Main(string[] args)
{
IList<Product> products = GetList();
IEnumerable<IGrouping<string, Product>> groups = products.GroupBy(a => a.category);
foreach (IGrouping<string, Product> group in groups)
{
Console.WriteLine(group.Key);
foreach (Product product in group)
{
Console.WriteLine(product);
}
}
//Electronics
//[1: Electronics - 15]
//[5: Electronics - 19.95]
//[10: Electronics - 250]
//Groceries
//[2: Groceries - 40]
//Garden
//[3: Garden - 210.3]
//[8: Garden - 13]
//Pets
//[4: Pets - 2.1]
//[6: Pets - 21.25]
//[7: Pets - 5.5]
//Automotive
//[9: Automotive - 10]
}
看起来一切都很好,没有什么问题.
当我们使用 GroupBy() 扩展方法时,使用了延迟执行。 这意味着,当你遍历集合的时候,下一个要出现的项目可能会或者可能不会被加载。 这是一个很大的性能改进,但它会引起有趣的副作用。
在用 GroupBy()时, 它实际上是在第一项被使用的时候创建分组,而不是在 GroupBy() 第一次被调用时。
static void Main(string[] args)
{
List<Product> products = GetList();
IEnumerable<IGrouping<string, Product>> groups = products.GroupBy(a => a.category);
//移除类别为Garden的产品
products.RemoveAll(a => a.category == "Garden");
foreach (IGrouping<string, Product> group in groups)
{
Console.WriteLine(group.Key);
foreach (Product product in group)
{
Console.WriteLine(product);
}
}
//Electronics
//[1: Electronics - 15]
//[5: Electronics - 19.95]
//[10: Electronics - 250]
//Groceries
//[2: Groceries - 40]
//Pets
//[4: Pets - 2.1]
//[6: Pets - 21.25]
//[7: Pets - 5.5]
//Automotive
//[9: Automotive - 10]
}
执行后发现,所有的Garden产品都已经消失了,但是 groups 是在执行删除命令前就已经赋值了。
基于这种情况,我们不得不使用ToDictionary() 将GroupBy 后的结果储存起来,这样一来工作量就增加了,而且维护也不太方便 – 请大家试试。
ToLookup登场
static void Main(string[] args)
{
List<Product> products = GetList();
ILookup<string, Product> looks = products.ToLookup(a => a.category);
//删除产品类别为Garden的产品
products.RemoveAll(a => a.category == "Garden");
foreach (IGrouping<string, Product> group in looks)
{
Console.WriteLine(group.Key);
foreach (Product product in group)
{
Console.WriteLine(product);
}
}
//Electronics
//[1: Electronics - 15]
//[5: Electronics - 19.9
//[10: Electronics - 250
//Groceries
//[2: Groceries - 40]
//Garden
//[3: Garden - 210.3]
//[8: Garden - 13]
//Pets
//[4: Pets - 2.1]
//[6: Pets - 21.25]
//[7: Pets - 5.5]
//Automotive
//[9: Automotive - 10]
}
你也可以通过索引器指定键来获得值
foreach (Product product in looks["Electronics"])
{
Console.WriteLine(product);
}