In order to solve a large number of similar elements, so the array is born and bred. An array is a collection of several objects that have a certain sequence of relationships, and one-dimensional arrays can be considered as linear tables with fixed lengths. Conversely, an array of n can be regarded as a generalization of a linear table. From the storage structure, the array is a contiguous storage space. Now let's look at the array in C #:
1. Normal array
In C #, ordinary arrays can also be divided into one-dimensional arrays, multidimensional arrays, and jagged arrays.
<1> One-dimensional arrays
Let's look at the declaration syntax for a one-dimensional array first:
Type [] variable name;
Knowing how to declare it, now let's look at the initialization of the array, in C # There are 4 ways to initialize it:
n is an array-length, an element-type [] in the Arrays name = new type [n]; Allocates memory for an array, but does not assign an initial value (vs automatically assigns it an initial value of 0) type [] Array name = new Type [N]{A1, A2, ..., an}//initialization, and assignment of the initial value type [] Array name = new Type []{A1, A2,..., an}//can also not specify array length , the compiler automatically counts the number of elements type [] Array name = {A1, a2,..., an}//c-style initialization and assignment
When accessing an array, the I-1 element is accessed in the form of "array name [i]". If you do not know the length of the array, you can use the Length property.
Note : If the element type in the array is a reference type, you must allocate memory for each element. In C #, "type []" is an indivisible whole, and "type []" can be considered an array type.
<2> Multidimensional Arrays
After reading a one-dimensional array, we now generalize to a multidimensional array, declaring the syntax:
Type [,] array name;//two-dimensional array type [,,] array name;//three-dimensional array
I'm sure you found it. The number of commas in square brackets + 1 is the number of dimensions of the array. Let's take a two-dimensional array as an example to see the initialization of multidimensional arrays:
int[,] arr = new int[2,3]{{1,2,3},{4,5,6}};
I would like to take this example to illustrate that the difference between a multidimensional array and one-dimensional array initialization is that when multidimensional arrays are initialized, each dimension must be enclosed in curly braces. The rest is the same as the one-dimensional array initialization method.
<3> Jagged arrays
In the process of using multidimensional arrays, we do not sometimes need to have the same dimensions in each dimension, so we introduce jagged arrays. (vectors in C + + also have similar functions). The previous picture illustrates the difference between a two-dimensional array and a jagged array:
Now let's look at his statement syntax:
Type [] Array name = new Type [n][];//n is a dimension of the jagged array, and the next square bracket is empty
Let's use a concrete example to see how he uses it:
int[][] Testarray = new int[2][]; Testarray[0] = new int[3]{1,2,3};//Of course can also first not assign the initial value, it is recommended to first assign the initial value testarray[1] = new int[4]{1,2,3,4};
At this time some people may have doubts about the length of each dimension is different, so how to simply traverse the entire array? The length attribute can then play its advantage. We take the above as an example:
for (int i = 0, i < testarray.length; i++) {for (int j = 0; J < Testarray[i]. Length; J + +) {//todo:}}
<4> Arrays as parameters
Since we consider an array to be a type, it can also be passed as a parameter to a method, or it can be returned from a method. C # Arrays also support covariance, but array covariance can only be used for reference types and not for value types.
<5> Array Segment Arraysegment<t>
Arraysegment<t> can create a mapping between and between arrays that directly manipulate a fragment of an array, whose results are directly reflected in the array, whereas changes on the array are reflected on the array segment. Let's take a look at the specific use:
arraysegment<int> Test = new Arraysegment<int> (arr, 1, 4);
The above example, which indicates test, starts with a reference to 4 elements from arr[1]. Test.offset represents the first referenced element, which is arr[1].
2. Array class
Before we used square brackets to declare an array, we actually used the array class implicitly. In another way, we use, for example: int[], double[] We can all think of them as a subclass derived from array, so we can use an array to define methods and properties for arrays.
<1> Create an array
Array is an abstract class, so it cannot be instantiated. However, you can use the static method CreateInstance () to create an array. Since CreateInstance () has more than one overloaded version, let's do one of the following:
Create an int type, an array of length 5, Testarray Test = Array.CreateInstance (typeof (int), 5), or//We will test[3] the value, assigned to 5test.setvalue (5, 3);// We want to return the value of Test[3] Test.getvalue (3);//convert it to int[] array int[] T1 = (int[]) Test;
<2> Copying Arrays
We can use the Clone () method to copy an array, but if the array is a reference type then you can only copy each other's references. If the array is a value type, it is possible to copy the other completely. We can also use the copy () method to create a shallow copy.
Note: Clone () and copy () The biggest difference: the copy () method must use the same order as the original array and have enough element space, but the cone () method creates a large array such as the original array.
<3> Sort
The array class also provides a quicksort sorting algorithm. Use the sort () method to sort the array. But using the sort () method requires implementing the IComparable interface (. NET has implemented the IComparable interface for basic data types, from small to large by default. For custom types, we must implement the Icomparable<t> interface, which uses only one method CompareTo (). If the two are equal, return 0. If the instance is preceded by a parameter object, it returns a value less than 0, and vice versa returns a value greater than 0.
We can also do this by implementing the icomparer<t> and IComparer interfaces. We now focus on the difference between this and the IComparable interface:
①icomparable is implemented in the class where you want to compare objects, you can compare the object and another object.
②icomparer to be implemented in a single class, you can compare any of the two objects.
3. Enumeration
Using enumerations in a foreach statement allows you to iterate over the elements in the collection without needing to know the number of elements in the collection. The foreach statement uses an enumerator, and we need to implement the IEnumerable interface to iterate over the collection using foreach. (Arrays and collections already implement the IEnumerable interface by default).
<1>foreach principle and IEnumerator interface
foreach uses the methods and properties of the IEnumerator interface.
Per is the object of the Person class, foreach (Var p in per) {Consle.writeline (P);}
The C # compiler resolves this code to
Ienumerator<person> em = per. GetEnumerator (); while (em. MoveNext ()) {person p = em. Current; Console.WriteLine (P);}
The MoveNext () method of the IEnumerator interface is to move to the next element of the collection and, if any, to return true, otherwise false. The current property is the value.
<2>yield statements
Since the work of creating the enumerator is too cumbersome, we introduced the yield statement to help us reduce the workload, yield return returns an element of the collection, and yield break can stop the iteration.
Below we can use a simple example to understand how yield is used:
public class Tfoo{public ienumerator<string> GetEnumerator () {yield return ' Hello '; yield return ' World ';}}
Now we'll iterate through the set with the foreach
int cnt = 0;//We use this to see if the collection iterates over several times in foreach var Test = new Tfoo (), and the foreach (Var s in Test) {cnt++; Console.WriteLine (s);}
Finally we can get CNT = 2 and will output Hello world. With this example, we can get a general idea of how yield works. We already used a yield in the list before learning generics.
Note : Yield cannot appear in anonymous methods
4, tuple (tuple)
Arrays are designed to handle a large number of similar types of data, so what can we do with different kinds of data in a similar way? Of course, we have introduced a tuple class for this purpose. NET defines 8 generic tuple classes, and a static tuple. For example,:tuple<t1> contains an element of type T1,tuple<t1,t2> that contains two elements of type t1,t2, and so on.
If the tuple element is more than 8 then the 8th one can use the tuple class definition, for example:
Tuple<t1, T2, T3, T4, T5, T6, T7, trest>//trest for another tuple
In this way, we can create tuples with any number of groups.
We create tuples using the Create () method, for example:
var Test = tuple.create<int,int> (2,5);
5. Structure comparison
Both arrays and tuples implement interfaces istructuralequatable and IStructuralComparable. These two interfaces can be used not only to compare references , but also to compare content . Because these interfaces are display implementations, it is necessary to force arrays and tuples into this interface when used.
The IStructuralEquatable interface is used to compare whether two arrays or tuples have the same content.
The IStructuralComparable interface is used to order arrays or tuples.
We use an example to simply understand the use of the IStructuralEquatable interface:
public class test{Public int Id {get; set;} public override bool Equals (object obj) { if (obj = = null) return base. Equals (obj); else return this. Id = = (obj as Test). Id;} }
We now define two class object t1,t2 with the same class content.
var t1 = new Test[2]{new Test{id = 2}, new test{id = 3}};var t2 = new Test[2]{new Test{id = 2}, new Test{id = 3}};
If we directly use "= =" or "! = "Comparison then the compiler will only compare our references." This is what we need to use the IStructuralEquatable interface.
(t1 as IStructuralEquatable). Equals (T2, Equalitycomparer<test>. Default)
So we compare the content of the T1,T2, because it is the content of the comparison, so they will return true. Equalitycomparer<test>. The default call is the Equals () method of test, so we can simply override the default Equals () method to the rule that overrides the content of the Equals () method class, then we could compare the class object to the same content.
For tuple e1,e2, we use E1 directly. Equals (E2) We can compare the contents between tuples, but the same if we can only compare their references with the comparison operator "= =" and "! =".
(If there is an error, please correct it, reproduced in the source)
"C # Advanced Programming", "The sixth chapter" array--Learning notes