Select item in list C#

List.Contains[T] Method is used to check whether an element is in the List or not.

Properties of List:

  • It is different from the arrays. A list can be resized dynamically but arrays cannot.
  • List class can accept null as a valid value for reference types and it also allows duplicate elements.
  • If the Count becomes equals to Capacity then the capacity of the List increases automatically by reallocating the internal array. The existing elements will be copied to the new array before the addition of the new element.

Syntax:

public bool Contains [T item];

Here, item is the object which is to be locate in the List. The value can be null for reference types.

Return Value: This method returns True if the item is found in the List otherwise returns False.



Below programs illustrate the use of List.Contains[T] Method:

Example 1:

using System;

using System.Collections;

using System.Collections.Generic;

class Geeks {

    public static void Main[String[] args]

    {

        List firstlist = new List[];

        firstlist.Add[1];

        firstlist.Add[2];

        firstlist.Add[3];

        firstlist.Add[4];

        firstlist.Add[5];

        firstlist.Add[6];

        firstlist.Add[7];

        Console.Write[firstlist.Contains[4]];

    }

}

Output:

True

Example 2:

using System;

using System.Collections;

using System.Collections.Generic;

class Geeks {

    public static void Main[String[] args]

    {

        List firstlist = new List[];

        firstlist.Add["Geeks"];

        firstlist.Add["For"];

        firstlist.Add["Geeks"];

        firstlist.Add["GFG"];

        firstlist.Add["C#"];

        firstlist.Add["Tutorials"];

        firstlist.Add["GeeksforGeeks"];

        Console.Write[firstlist.Contains["Java"]];

    }

}

Output:

False

Reference:


List.Item[Int32] Property is used to gets or sets the element at the specified index.

Properties of List:

  • It is different from the arrays. A list can be resized dynamically but arrays cannot.
  • List class can accept null as a valid value for reference types and it also allows duplicate elements.
  • If the Count becomes equals to Capacity then the capacity of the List increases automatically by reallocating the internal array. The existing elements will be copied to the new array before the addition of the new element.

Syntax:

public T this[int index] { get; set; }

Parameter:

index: It is the zero-based index of the element to get or set of type System.Int32.



Return Value: This property returns the element at the specified index.

Exception: This method will give ArgumentOutOfRangeException if the index is less than 0 or index is equal to or greater than Count.

Below are the examples to illustrate the use of List.Item[Int32] Property:

Example 1:

using System;

using System.Collections.Generic;

class Geeks {

    public static void Main[String[] args]

    {

        List firstlist = new List[];

        firstlist.Add["A"];

        firstlist.Add["B"];

        firstlist.Add["C"];

        firstlist.Add["D"];

        firstlist.Add["E"];

        firstlist.Add["F"];

        Console.WriteLine["Element at index 2: " + firstlist[2]];

    }

}

Output:

Element at index 2: C

Example 2:

using System;

using System.Collections.Generic;

class Geeks {

    public static void Main[String[] args]

    {

        List firstlist = new List[];

        firstlist.Add["A"];

        firstlist.Add["B"];

        firstlist.Add["C"];

        firstlist.Add["D"];

        firstlist.Add["E"];

        firstlist.Add["F"];

        Console.WriteLine["Element at index 2: " + firstlist[2]];

        firstlist[2] = "Z";

        Console.WriteLine["After Setting the new value at 2: " + firstlist[2]];

    }

}

Output:

Element at index 2: C After Setting the new value at 2: Z

Reference:


While the others have basically presented you with some solutions, i want to focus on what you actually looking at ^^. First the "Where" method is an extension method for IEnumerables. It basically takes an input IEnumerable as well as a "predicate method", it "processes" the input collection and returns a new IEnumerable. For each element in the input collection it runs the predicate and if it returns "true" that element will go into the output. If not it's basically skipped.

Now i used some terms here which i might explain shortly:

IEnumerable

An IEnumerable is basically just an interface that provides you of a way to get an "IEnumerator". Therefore the only method that the interface provides is called "GetEnumerator". So what the heck is an IEnumerator then?

IEnumerator

You may already heared about that interface when you used or read about coroutines in Unity. However Unity just uses this interface to implement coroutines.

The IEnumerator actually is just an interface that allows you to "iterate" over "things". To keep it simple we just focus on two things: An IEnumerator has a method called "MoveNext" and a property called "Current".

MoveNext simply moves the iterator "forward" to the next element. Further more it returns a boolean indicating if we reached the end of the iteration. A value of "false" means there are no more elements and we're done. A value of "true" means the iterator found another object and "Current" can be used to access that object. So when iterating the IEnumerator we always call MoveNext first, see if it returns true, then access the current element. If it returns false we stop iterating.

Since IEnumerable and IEnumerator are interfaces they need to be implemented by actual objects. A lot of classes implement the IEnumerable interface [like the generic List for example]. Each object usually has their own enumerator class which implements the IEnumerator interface which does the actual iteration. So when calling GetEnumerator on a List object it will create an instance of that enumerator object.

Normal vs Generic

It might be worth mentioning that both interfaces come in a "normal" / untyped version and a generic "typed" version. Most of the Linq stuff will work on the generic version only. So the generic version basically just let you specify the exact type of objects the iterator will spit out. i.e. the type of the Current property.

Chaining enumerators

What most of those Linq extension methods do is basically creating wrapper objects which also implement IEnumerable / IEnumerator around the input IEnumerable / IEnumerator. So when you call MoveNext on the wrapper it will in turn call MoveNext on the input enumerator to get one element from the input and returns that one as Current.

For example:

List someList; IEnumerable myEnumerable = someList.Where[x=>x != "not me"]; foreach[string s in myEnumerable] { Debug.Log[s]; }

Note that in the second line we just create the "wrapper" IEnumerable. We don't iterate it. The foreach loop will actually call GetEnumerator and then iterate over each item that the wrapper object returns, While iterating the wrapper will in turn iterate over the input enumerator. This "chaining" can go crazy.

Predicate function

A predicate is actually a method that will tell the caller if a certain object satisfies a certain criteria. It's actually just a method that takes an object as parameter and returns a boolean. In most cases when using Linq you would use Lambda expression / anonymous method, but you can use actual methods as well. The example above could be written as: static bool FilterOutNotMe[string aObj] { if [aObj == "not me"] return false; return true; } IEnumerable myEnumerable = someList.Where[FilterOutNotMe];

Lambda expression

A Lambda expression is basically just an anonymous method. The syntax is fairly easy. You first have to specify the paramters of your method, followed by the lambda operator =>. Behind that operator you actually specify the body of your method. The formal syntax would look like this: [Type variableName1, Type variableName2] => { /* code */ }

This basically defines a method seemingly ad-hoc that can be passed as delegate to methods that require such a callback method. Now there are a few simplifications. First of all if you pass the lambda expression as parameter to another method, the compiler can figure out [infer] the types of the parameters based on the expected type of the expected delegate type. So one could simply omit the types and just define the parameters:

[a, b] => { }

Furthermore if there's only one parameter [and you don't need to specify the type explicitly] you can omit the brackets [ ] around the parameters:

Action myAction = a => { Debug.Log["a is " + a]; };

So in this example the compiler will infer that the type of the parameter "a" is "int". When you now call myAction[5] it will actually print "a is 5" in the console. It will also infer the return type is one is required

Func myFunc = a => { return "FooBar " + a; };

The last simplification is that if you only have one statement in your method body you can omit the curly brackets as well. In the case of a method with return type that single statement has to evaluate to the expected return type. You also have to omit the "return" keyword in this case. So the above example becomes this:

Func myFunc = a => "FooBar " + a;

Where

As mentioned above the Where method takes a predicate which is evaluated for each element as the enumerator is iterated. What the enumerator class for the Where method basically looks like is something like this: // written by me from scratch class Where_Enumerator : IEnumerator { IEnumerator input; Predicate condition; public T Current { get { return input.Current; } } public bool MoveNext[] { while[true] { if [!input.MoveNext[]] return false; if [condition[input.Current]] return true; } } }

So each time MoveNext is called it will advance the input enumerator and if we reach the end of the input stream, return false. Otherwise call the predicate method with the current element from the input enumerator. If the predicate returns true we return true so the current element should be processed by who ever currently is iterating over our enumerator, If the predicate returns false, so the element should not be returned, we simply keep looping and pulling the next element from the input until we get one that satisfies our condition or we reach the end of the input stream.

Select

The Select method is a bit different as it can have different input and output types. It also takes a delegate as parameter, but this time a selector method instead of a predicate. A selector method takes an object from the input enumerator as parameter and returns the desired output type. So in the case of your code sample Select[go => go.transform] the lambda expression will take a CharacterMotor as parameter [as this is the type of the input enumerator] and returns a Transform. The Transform type is inferred from whatever you actually return.

So Select creates another wrapper around it's input enumerator and to each element from the input it applies the "converting" / selecting callback.

Things to keep in mind

As mentioned above chaining enumerators have the advantage that in the end you only iterate through your base collection only once and each element will go through the whole chain, one by one.

However there are some methods that might break that rule because it's necessary for their correct behaviour. For example "OrderBy" or "Reverse". They actually need to iterate through the whole input collection and store all the elements in an internal structure in order to perform any sorting or the reverse of the collection.

There are also "ending" methods like ToList[], ToArray[], Count[], Sum[], Max[], ... which obviously will iterate through the current stack of enumerators since they also need access to all elements.

Short addition to lambda expressions [closures!]

I didn't mention that above since it's a topic on it's own but lambda expression as well as anonymous methods basically come in two variations:

A simple method is just what an ordinary method looks like. It has parameters and might return a value. However they do not reference anything outside the methods body. Basically a simple method is any lambda expression you could write as a normal static method [like my "FilterOutNotMe" example above].

A closure is a real beast. It's a method that actually references variables outside the scope of the own methods body. Those external variables are said to be closed upon / around. But how the heck does this work? Well, in both cases the code for those methods is not generated at runtime as some people believe but completely generated at compile time. But how is a method able to use variable from a completely different scope? The answer is the compiler creates a new internal class which acts as "shared scope". So using a closure actually affects the code that is generated for the outer scope as well. Simple example:

Func Method[] { int myInt = 6; Func myClosure = []=>myInt; Debug.Log["myInt: " + myInt]; return myClosure; }

As we all know myInt is a local variable of "Method". It's allocated on the stack when we enter the method and automatically freed when the method ends. However not in this case. Because our closure uses "myInt", the compiler will generate a closure class which will contain the variable myInt. Every point where you use myInt will be replaced by the class variable.

Rough example what happens under the hood:

private class Closure123 { public int myInt; public int Closure123_456[] { return myInt; } } Func Method[] { Closure123 c = new Closure123[]; c.myInt = 6; Func myClosure = c.Closure123_456; Debug.Log["myInt: " + c.myInt]; return myClosure; }

As you can see the compiler will create a new instance of the closure class and every access to myInt has been changed to use the closure instance now. Also our lambda expression is simply a member method of the closure class where it can easily access the variable.

When "Method" finished all of it's local variable will go out of scope and extend which includes the "c" variable that holds our closure object. However since the method returns the myClosure delegate, the actual object reference is stored inside that delegate so the closure object as well as the myInt variable will survive.

When you call "Method" again a new closure object will be created.

Damn, the "short" turned out longer than i expected ^^. It's difficult for me to explain things in a short way ^^. Hopefully it helps so you get a better understanding of enumerators, lambda expressions and Linq.

Video liên quan

Chủ Đề