您的位置:首页 > 其它

(13)支持标准查询运算符的集合接口

2011-11-14 09:56 477 查看
*匿名类型和隐式类型的局部变量声明

*集合初始化器

集合初始化器想要编译成功,需要满足几个条件:

1.集合类型应该实现了System.Collections.Generic.ICollection<T>接口,这样就可以保证集合可以使用Add()方法。另一个比较宽松的条件是只要求实现了IEnumerable<T>类型的一个或者多个Add()方法,即使没有实现ICollection<T>的Add方法。

2.匹配方法名,而且方法的签名要和集合的初始化项兼容,所以可以在集合中初始化更加多样化的数据项。

//使用集合初始化器
static void Main(string[] args)
{
//List<string> sevenWorldBlunders= new List<string>()
//如果没有参数可以省略圆括号。
List<string> sevenWorldBlunders= new List<string>
{
"Wealth without work",
"Pleasure without conscience",
"Knowledgr without chararcter",
"commerce without morality",
"Scinence wihtout humanity",
"worship without sacrifice",
"politicd without principle"
};
Print(sevenWorldBlunders);

}

private static void Print<T>(IEnumerable<T> items)
{
foreach (T item in items)
{
Console.WriteLine(item);
}
}


3.匿名类型是不能使用集合初始化器的,因为集合初始化器要求调用一次构造函数。解决的方法

(1)可如下定义一个方法:

static List<T> CreateList<T>(T t) {return new List<T>;}

(2)使用数组初始化器解决匿名类型的集合初始化。

var worldCup2006Fimalists = new[]
{
new
{
TeamName="France",
Players  =new string[]
{
"Fabiden Barthez",
"Geregory Coupet",
"Mickael Landreau",
"Eric Abidal"
}
},
new
{
TeamName="Italy",
Players=new string[]
{
"Gianluigi buffon",
"Angelo Peruzzi",
"Marco Amelia ",
"Cristian Zaccardo"
}
}
};
**foreach和IEnumerable<T>
一种更常规的方式遍历集合元素:迭代器(iterator):只要你能确定第一个元素,下一个元素和最后一个元素,就不需要知道元素的总数,也不需要按照索引来获取元素。
System.Collection.Generic.IEnumrator<T>和System.Collection.Generic.IEnumrator接口的设计目标就是允许迭代器模式来遍历元素集合。

IEnumerator<T>是从IEnumerator 和IDisposable派生,IEnumerator 后者包括三个成员,bool MoveNext():从一个元素移动到下一个元素,越过集合末尾之后返回false。只读属性Current,返回当前元素。第三个Rest():一般抛出一个NotImplementedException,所以永远都不调用它。

使用IEnumrator的前两个成员和属性和while组合就可以遍历集合中的元素。

IEnumrable<T>从IEnumrable派生。唯一的方法 就是GetEnumrator():返回支持IEnumrator<T >的一个对象,以解决交错的循环可能相互干扰的问题。 zai

            Stack<int> stack = new Stack<int>();
            int number;
            Stack<int>.Enumerator enumrator;
            //状态清理声明
            IDisposable disposable;
            stack.Push(1);
            stack.Push(2);
            stack.Push(3);
            stack.Push(4);
            stack.Push(5);
            //if IEnumrable<T> is implemented explicity,
            //then a cast is Required.
            //((IEnumrable<int>stack).GetEnumrator());
           enumrator = stack.GetEnumerator();
           try
           {
               while (enumrator.MoveNext())
               {
                   number = enumrator.Current;
                   Console.WriteLine(number);
               }
           }
           finally
           {
               //IEnumrator will use the as operator unless Idisposable
               //support is know at compile time;
               //disposable=(enumrrator as IDisposable)
               //if(disposable!=null)
               //{
               //    disposable.Dispose();
              // }
               disposable = (IDisposable)enumrator;
               disposable.Dispose();
           }
            Console.ReadKey();
**使用using的错误处理和资源清理:

//使用using的错误处理和资源清理
using (   System.Collections.Generic.Stack<int>.Enumerator enumrator
= stack.GetEnumerator())
{
while (enumrator.MoveNext())
{
number = enumrator.Current;
Console.WriteLine(number);
}
}
**foreach 循环内不要修改集合。

**标准查询运算符

using System.Linq   只用这句话,就可以使用IEnumrable<T>的多个方法--------标准查询运算符(stand query operator),它提供了对它操作的集合查询的能力。

放代码:

public class Patent
{
public string Title { set; get; }
public string YearOfPublication { set; get; }
public string ApplicationNumber { set; get; }
public long[] InventorIds { set; get; }
public override string ToString()
{
return string.Format("{0}  {1} ",Title,YearOfPublication);
}
}

public class Inventor
{
public long Id { set; get; }
public string Name { set; get; }
public string City { set; get; }
public string State { set; get; }
public string Country { set; get; }
public override string ToString()
{
return string.Format("{0} {1}, {2}",Name,City,State) ;
}
}
public static class PatentData
{
public static readonly Inventor[] Inventors = new Inventor[]
{
new Inventor(){
Name="Benjamin Franklin",City="PhiladelPhia",State="PA",
Country="USA",Id=1},
new Inventor(){
Name="Orville Wright",City="Kitty Hawk",State="NC",
Country="USA",Id=2},
new Inventor(){
Name="Wilbur Wright",City="Kitty Hawk",State="NC",
Country="USA",Id=3},
new Inventor(){
Name="Samuel Morse",City="New York",State="NY",
Country="USA",Id=4},
new Inventor(){
Name="Jeorge Stephenson",City="Wylam",State="Northumberland",
Country="UK",Id=5},
new Inventor(){
Name="John Michaelis",City="Chicago",State="IL",
Country="USA",Id=6},
new Inventor(){
Name="Mary Phelps Jacob",City="New York",State="NY",
Country="USA",Id=7}
};

public static readonly Patent[] Patents = new Patent[]
{
new Patent(){
Title ="Bifocals",YearOfPublication="1784", InventorIds=new long[]{1}},
new Patent(){
Title ="Phonograph",YearOfPublication="1877", InventorIds=new long[]{1}},
new Patent(){
Title ="Kinetoscope",YearOfPublication="1888", InventorIds=new long[]{1}},
new Patent(){
Title ="Electrical Telegraph",YearOfPublication="1837", InventorIds=new long[]{4}},
new Patent(){
Title ="Flying machine",YearOfPublication="1903", InventorIds=new long[]{2,3}},
new Patent(){
Title ="Steam Locomotive",YearOfPublication="1815", InventorIds=new long[]{5}},
new Patent(){
Title ="Droplet deposition appearatus",YearOfPublication="1989", InventorIds=new long[]{6}},
new Patent(){
Title ="Backless Brassiere",YearOfPublication="1914", InventorIds=new long[]{7}},
};
}
    class Program
    {
        static void Main(string[] args)
        {
            IEnumerable<Patent> patents =PatentData.Patents;
            //为了从集合中筛选出某些数据,需要提供一个筛选器方法来返回true 或false ,从而表明一个特定的元素是否应该被包含进来。
            //获取一个实参,并返回一个布尔值的委托表达式称为一个谓词。集合where()方法依据谓词来判断筛选条件。
            //where代码将筛选的结果返回给IEnumrable<T>,是一个新的集合。
            //where()方法的表达式实参并非一定是在赋值时求值的。(没理解啥意思)
            IEnumerable<Patent> patentsOf1800 = patents.Where(patent => patent.YearOfPublication.StartsWith("18"));
            //由于where()输出的是一个新集合,所以可以在此上面进行数据转换。
            
           
            //理解:select不同于SQL中的select,这里是一种类似于将类型A投射成类型B的形式。
            IEnumerable<string> items = patentsOf1800.Select(patent=>patent.ToString());

            //使用select和new来投射
            //IEnumerable<string> fileList = Directory.GetFiles(@"D:\C#学习\C#Sample\DataSamples\Entity Framework\Tests","*.cs");
            //IEnumerable<FileInfo> files = fileList.Select(file=> new FileInfo(file));

             //投射到一个匿名类型
             // IEnumerable<string> fileList = Directory.GetFiles(@"D:\C#学习\C#Sample\DataSamples\Entity Framework\Tests","*.cs");
             //var s = fileList.Select(file =>   【替换成 var s = fileList.AsParallel().Select(file =>,运行时一边遍历,一边返回结果对象,实现LINQ的并行查询】
             //   {
             //      FileInfo fileInfo = new FileInfo(file);
             //       return new
             //       {
             //           FileName = fileInfo.Name,
             //           Size = fileInfo.Length
             //       };
             //   });

            //Count()
            //Count()语句是遍历了集合中的所有项,所以最好只用IEnumrable<T>的Count属性。
            //如果一个集合支持ICollection<T>,再调用Count()语句,会对集合转型,并调用Count。
            //如果集合不支持ICollection<T>,Enumrable.Count()就会枚举集合中的所有项,而不是调用内建的Count。
            //如果计数的目的只是和0比较,则用patents.Any()即可,只要尝试遍历集合中的一个项,成功则true,否则false。
            Console.WriteLine("Patent count :{0}",patents.Count());
            Console.WriteLine("Patent count in 1800: {0}",patents.Count(patent=>patent.YearOfPublication.StartsWith("18")));
            Console.WriteLine();

            Print(items);
            Console.WriteLine();
            IEnumerable<Inventor >inventors=PatentData.Inventors;
            Print(inventors);
            Console.ReadKey();
        }
        private static void Print<T>(IEnumerable<T> items)
        {
            foreach (T item in items)
            {
                Console.WriteLine(item);
            }
        }
    }
**推迟执行(LINQ)

上面代码看着乱了,把一些注释删掉。

//LINQ的推迟执行
static void Main(string[] args)
{
int count=0;
IEnumerable<Patent> patents = PatentData.Patents;
bool result;
//2
//***Where()方法的表达式实参并非一定是在赋值时求值的,着适用于许多标准查询运算符。
//***在Where条件下,表达式传给集合,“保存”但不马上执行。
//***只有在需要遍历集合中的项时,才会真正对表达式求值。
//lamda表达式是可以传递到别的地方的委托---是一个对方法的引用。
patents = patents.Where(patent =>
{
//1.任何谓词都只应做一件事情:多一个条件进行求值。它不应该有任何“副作用”(比如本例中打印到控制台)。
if (result = patent.YearOfPublication.StartsWith("18"))
{

Console.WriteLine("\t{0},{1}",patent,count++);
}
return result;
});
Console.WriteLine("1.Patent prior to the 1900s are :");
//foreach()语句触发了Lamda表达式。
//foreach()被分解成MoveNext(),涉及调用了集合的每一项.
foreach(Patent patent in patents)
{
}
Console.WriteLine();
Console.WriteLine("2.A second listing of patents prior to the 1900s:");
//patents.Count()触发了lamda表达式。
Console.WriteLine("  There are {0} patents prior to the 1900s:",patents.Count());
Console.WriteLine();
Console.WriteLine("3.A third listing of the patnent prior to the 1900s:");
//.ToArray(ToList(),ToDictionary(),ToLookup())的ToXXXX()方法对转换集合是相当有用的,这样返回的标准查询运算符已经处理过的一个集合。
//ToXXXX()方法转换成一个集合类型之后,一般可以安全的操作集合。但会造成整个结果集加载到内存中,
//ToXXXX()方法会创建基础数据的“快照”,确保在重新查询ToXXXX()结果时,不会返回新的结果。
patents = patents.ToArray();
Console.Write("  There are ");
Console.WriteLine("{0} patents prior to 1900.",patents.Count());
Console.ReadKey();
}
就结果显示:

1.Patent prior to the 1900s are :

        Phonograph  1877 ,0

        Kinetoscope  1888 ,1

        Electrical Telegraph  1837 ,2

        Steam Locomotive  1815 ,3

2.A second listing of patents prior to the 1900s:

        Phonograph  1877 ,4

        Kinetoscope  1888 ,5

        Electrical Telegraph  1837 ,6

        Steam Locomotive  1815 ,7

  There are 4 patents prior to the 1900s:

3.A third listing of the patnent prior to the 1900s:

        Phonograph  1877 ,8

        Kinetoscope  1888 ,9

        Electrical Telegraph  1837 ,10

        Steam Locomotive  1815 ,11

  There are 4 patents prior to 1900.

  

**使用OrderBy()和ThenBy()来排序。

//使用OrderBy和ThenBy
static void Main(string[] args)
{
IEnumerable<Patent> items = PatentData.Patents;
Patent[] patents = PatentData.Patents;
//OrderBy返回的是一个IOrderedEnumrable<T>接口,是从IEnumrable<T>派生的。
//对OrderBy的返回集合使用OrderBy,会撤销上一个OrderBy,只有最后一个的OrderBy()的keySelector才真正起作用。
//ThenBy()是针对IOrderedEnumrable<T>
items=patents.OrderBy(
patent => patent.YearOfPublication).ThenBy(
patent => patent.Title);
Print(items);
Console.WriteLine();
items=patents.OrderByDescending(
patent => patent.YearOfPublication).ThenByDescending(
patent => patent.Title);
Print(items);

Console.ReadKey();
}
**连接(join)操作

*Inner LeftOuter
RightOuter

*//一个内连接的例子,类的结构与上述代码中类似

public class Department
{//...
}
public class Employee
{//...
}
public static class CorporateData
{
public static readonly Department[] Departents=new Department[]
{
//...
};
public static readonly Employee[] Employees = new Employee[]
{
//
};
}
class Program
{
static void Main(string[] args)
{
Department[] departments = CorporateData.Departents;
Employee[] employees = CorporateData.Employees;

var items = employees.Join(
departments,                        //内连接的对象
employee => employee.DepartmentId,  //outerKeySelector1
department => department.Id,        //outerKeySelector2与outerKeySelector1相等才是内连接的筛选条件。
(employee, department) => new       //使用匿名类型对结果集进行选取。
{
employee.Id,
employee.Name,
employee.Title,
Department=department           //用一个Department属性来存储连接的department的对象。

});
}
}
***使用GroupBy分组结果

IEnumrable<Employee> employees= CorporateData.Employees;

IEnumrable<IGrouping<int,Employee>> groupedEmployees= employees.GroupBy((employee)=>employee.DepartmentId);

***使用GroupJoin()实现一对多

//一个部门对应多个员工

    Department[] departments = CorporateData.Departents;

            Employee[] employees = CorporateData.Employees;

            var items =departments.GroupJoin(employees ,                 //内连接的对象

                department => department.Id, //outerKeySelector1

              employee => employee.DepartmentId,
      //outerKeySelector2与outerKeySelector1相等才是内连接的筛选条件。

                (department, departmentEmployees)=>new  //使用匿名类型对结果集进行选取。

                {

                    department.Id,

                    department.Name,

                    Employee=departmentEmployees           //Func<Department,IEnumrable<Employee>,TResult>,其中TResult是所选的匿名类型。使用的第二个参数是将每个部门的员工集合投射到结果的部门匿名类型中。
    });  

所以在遍历该匿名类型是,应该使用两个foreach来遍历,里面的用来遍历对于一个部门下的员工集合。

**使用GroupJoin()和SelectMany()实现外连接。

            //使用GroupJoin和SelcetMany()实现外部连接。

            Department[] departments = CorporateData.Departents;

            Employee[] employees = CorporateData.Employees;

            var items = departments.GroupJoin(

                employees,                       

                department =>department.Id, 

                employees =>employee.DepartmentId,       

                (department,departmentEmployees ) => new     

                {

                    department.Id,

                    department.Name,

                   Employees=departmentEmployees         

                }).SelectMany(

                departmentRecord=>departmentRecord.Employees.DefaultIfEmpty(),

                departmentRecord,employ)=>new{

                    departmentRecord.Id,

                    departmentRecord.Name,

                    Employees=departmentRecord.Employees

                }).Distint();


*调用SelectMany()处理有集合构成的集合。

与Select()不用,对应不同的集合返回相对应的集合,SelectMany()返回的是几个集合的整合。

static void Main(string[] args)
{
IEnumerable<object> stuff = new object[] { new object(), 1, 3, 5, 7, 9, "\"thing\"", Guid.NewGuid() };
Print("stuff", stuff);

IEnumerable<int> even = new int[] { 0, 2, 4, 6, 8 };
Print("enen integer", even);
//根据指定类型筛选。
IEnumerable<int> odd = stuff.OfType<int>();
Print("Odd Integer ", odd);
//生成两个序列的并集。
IEnumerable<int> numbers = even.Union(odd);
Print("Union of odd and even", numbers);

Print("number Union with even", numbers.Union(even));
//连接两个序列。
Print("Concat Union with odd", numbers.Concat(odd));
//生成两个序列的交集。
Print("InterSection with even:{0}", numbers.Intersect(even));
//distinct()非重复元素
Print("Distinct\n", numbers.Concat(odd).Distinct());
if (!numbers.SequenceEqual(numbers.Concat(odd).Distinct()))
{
throw new Exception("Unexpectedly unequal");
}
else
{
Console.WriteLine(@"Collection""SequenceEquals""" + "collection.Concat(odd).Distinct()");
Print("Reverse ", numbers.Reverse());
Print("Average {0}", (numbers.Average()));
Print("Sum {0}", numbers.Sum());
Print("Min {0}", numbers.Min());
}
Console.ReadKey();

}
private static void Print<T>(string newstring, IEnumerable<T> items)
{
Console.Write(newstring + " : ");
foreach (T item in items)
{
Console.Write(item + ", ");
}
Console.WriteLine();
}
private static void Print<T>(string newstring, T item)
{
Console.WriteLine(newstring, item);
}

结果如下:

stuff : System.Object, 1, 3, 5, 7, 9, "thing", a9e7a0fc-80a6-40c6-bbd6-131a6e275

049,

enen integer : 0, 2, 4, 6, 8,

Odd Integer  : 1, 3, 5, 7, 9,

Union of odd and even : 0, 2, 4, 6, 8, 1, 3, 5, 7, 9,

number Union with even : 0, 2, 4, 6, 8, 1, 3, 5, 7, 9,

Concat Union with odd : 0, 2, 4, 6, 8, 1, 3, 5, 7, 9, 1, 3, 5, 7, 9,

InterSection with even:{0} : 0, 2, 4, 6, 8,

Distinct

 : 0, 2, 4, 6, 8, 1, 3, 5, 7, 9,

Collection"SequenceEquals"collection.Concat(odd).Distinct()

Reverse  : 9, 7, 5, 3, 1, 8, 6, 4, 2, 0,

Average 4.5

Sum 45

Min 0

  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息