Is there any Count method for IEnumerable in VB.NET? - vb.net

In C# if I have the following object:
IEnumerable<Product> products;
and if I want to get how many elements it contains I use:
int productCount = products.Count();
but it looks like there is no such method in VB.NET. Anybody knows how to achieve the same result in VB.NET?

Count is available in VB.NET:
Dim x As New List(Of String)
Dim count As Integer
x.Add("Item 1")
x.Add("Item 2")
count = x.Count
http://msdn.microsoft.com/en-us/library/bb535181.aspx#Y0

In later versions of .net, there is an extension method called Count() associated with IEnumerable<T>, which will use IList<T>.Count() or ICollection.Count() if the underlying enumerator supports either of those, or will iteratively count the items if it does not.
An important caveat not always considered with this: while an IEnumerable<DerivedType> may generally be substituted for an IEnumerable<BaseType>, a type which implements IList<DerivedType> but does not implement ICollection may be efficiently counted when used as an IEnumerable<DerivedType>, but not when cast as IEnumerable<BaseType> (even though the class would support an IList<DerivedType>.Count() method which would return the correct result, the system wouldn't look for that--it would look for IList<BaseType> instead, which would not be implemented.

In general, IEnumerable won't have a Count unless the underlying collection supports (eg List).
Think about what needs to happen for a generic IEnumerable to implement a Count method. Since the IEnumerable only executes when data is requested, in order to perform a Count, it needs to iterate through till the end keeping track of how many elements it has found.
Generally, this iteration will come to an end but you can setup a query that loops forever. Count is either very costly time-wise or dangerous with IEnumerable.

Related

Finding max in generic list directly

I have a generic C++ CLI list which is populated with integers. I want to find the max value. Normally the list is sorted in ascending order. So I could just take the last item. Or I could sort the list and then take the last item but is there a way to avoid that and just do something like ->Max()?
System::Collections::Generic::List<System::Int32>^ Testlist = gcnew System::Collections::Generic::List<System::Int32>();
Testlist->Add(1);
Testlist->Add(2);
Testlist->Add(3);
Testlist->Add(4);
int max = Testlist[Testlist->Count-1];//too iffy..without having to sort, can I get max?
Call the Linq method to find the Max of an IEnumerable.
using namespace System::Linq;
List<Int32>^ list = ...;
Int32 max = Enumerable::Max(list);
C++/CLI doesn't support the fancy Linq query syntax, nor extension methods, but all extension methods are just static methods, and you can call that directly. (In C#, we could use the extension method to write list.Max().)

How to reduce dimension?

Let us consider that I have an IEnumerable(Of IEnumerable(Of Integer)). All the inner IEnumerables contain IDs. I would like to gather all the IDs Distinctly into an IEnumerable(Of Integer). I can do that if I do something like this:
Dim result as New List(Of Integer)
For Each element In IDs
result.AddRange(element)
Next
result = result.Distinct
I have two problems with this approach:
- I have to write the iteration code when there is probably a Function for this purpose that I am unaware of
- The result is a List and I would like to keep the class of the inner IEnumerable
Is there a handy LINQ way to do this?
EDIT:
This question is different from this one, since I am speaking about IEnumerables, not Lists. Yes, I am aware that every List is an IEnumerable, but I am also aware that not every IEnumerable is a List. As a result, this is a more general question than the one which was marked as duplicate, as I have specified in my original question that I would like to maintain the Class of the inner IEnumerable in the result. If it was an array, I prefer to use an array.
You could use SelectMany extension method to flatten the structure, once flatten look for Distinct
result = IDs.SelectMany(Function(x) x).Distinct();
check this Demo

Convert or Cast from StringCollection to ObjectCollection?

I would like to populate a listbox with a list of installed printers in VB.net.
This works:
Dim printerList As System.Drawing.Printing.PrinterSettings.StringCollection
printerList = System.Drawing.Printing.PrinterSettings.InstalledPrinters
For Each printerName In printerList
ListBox1.Items.Add(printerName)
Next
This does not work:
ListBox1.Items.AddRange(printerList)
...because of the following type-conversion error:
Public Sub AddRange (value As
System.Windows.Forms.ListBox.ObjectCollection)': Value of type
'System.Drawing.Printing.PrinterSettings.StringCollection' cannot be
converted to 'System.Windows.Forms.ListBox.ObjectCollection'.
Is it possible to directly cast one to the other for use in AddRange() as shown? Or is the loop the only (or most efficient) way?
Well, you're dealing with 2 collections that were created before the more modern generic lists and enumerables, so their use is less fluid.
In this case, the AddRange method accepts either another ObjectCollection instance (not your case), or an array of Objects. If you want to benefit from the latter, you'll need to transform the StringCollection instance to an array of Objects. Here is how this can be done:
ListBox1.Items.AddRange(printerList.Cast(Of Object)().ToArray())
That said, I would stick with your current For Each loop. It is very readable, and doesn't create an intermediate array. But, I doubt either choice will make much difference, so pick your favorite.

Is it possible to get the nth item in a tuple?

I am passing a few optional arguments to a function as a tuple, since all of these have to be passed together or not at all. I would like to be able to iterate over the elements of the tuple numerically, and perform an operation on each item. For example:
Public Function myFunction(Optional t As Tuple(Of Integer, String, SomeType) = Nothing) As Integer
For i = 0 to 2
someCollection(i).someMethod(t(i)) 'Pseudocode for accessing ith item in tuple
Next
End Function
One way to resolve the problem would be to use a list, but then I lose the ability to enforce the number of members (which will always be fixed) and the types of each member. Another way would be to write out the statement three times with t.Item1, t.Item2 etc, but this is ugly.
Is there any way to access the nth item in a tuple?
Note: I would like to accomplish this with a tuple if at all possible, even though I am aware I could create alternate method signatures.
(Sure, I’ll turn this into an answer!)
You can put the items into an array for convenience; maintaining the type isn’t really an issue at that point, since if you’re doing the same thing with all of them they need to have some sort of common base class or interface.
Dim a() As Object = {t.Item1, t.Item2, t.Item3}
Then just iterate over that.

Creating a function that uses a generic structure?

I am attempting to create a generic function that the students in my introductory VB .NET course can use to search a single dimension array of a structure.
My structure and array look like this:
Private Structure Survey
Dim idInteger As Integer
Dim membersInteger As Integer
Dim incomeInteger As Integer
Dim stateString As String
Dim belowPovertyLevelBoolean As Boolean
End Structure
Private incomeSurvey(199) As Survey
My generic function header looks like:
Private Function FindSurveyItem(Of xType As Structure)
(ByVal surveyIDInInt As Integer, ByVal surveyArrayIn() As xType) As Integer
??????
End Function
My call to the function looks like:
If FindSurveyItem(Of Survey)(CInt(idTextBox.Text), incomeSurvey) <> -1 Then
My question is: Is there a way to reference the individual structure fields in the array from inside the function? I was trying to make it generic so that the student could simply pass their array into the function - their structure may be named differently than mine and the field names may be different.
I suspect there are other ways to deal with this situation, but I was trying to keep it to just a simple single-dimension array of a structure. I don't think it is possible to do what I want, but I wondered what others thought.
Is there a way to reference the individual structure fields in the array from inside the function?
Generic instead of an array you need a collection type. Add LINQ Code:
Dim Surveys = From svys In xType
Where svys.idInteger = surveyIDInInt
Select svys
For Each rSurveys In svys
'''' Your Code
Next
This is rough answer fill in the details (I know imagine LINQ without SQL DB!!)
If you have a genric type parameter T you are only able to access members of instances of T that are known to exist at compile time. As every type derives from Object you have only the members of Object availiable - ToString(), GetType(), GetHashCode(), and Equals().
If you want to access other members you have to constrain what T is allowed to be. In your situation a interface would be the way to go. See MSDN for details.
You could also try to use reflection or check the actual type at runtime an perform a cast. The first is hard to impossible to do if you do not know much about the types you will get. And the later requires you to know possible types at compiletime and will not work in your situation, too.
Another way might be to pass a delegate to the search method that performs the actual comparison.
What you're looking for are predicates, if using ,net 3.5
dim arr() as structure
Array.Find(arr, function(item)(item.MyMember = MemberToMatch))
More combersome in earlier versions, see here for more info
The point being, that your function would look very like an implementation of Array.Find (if you didn't want to use the function provided), and the students would need to write their own predicate function.
No, there isn't. You can't know the type at compile time, therefore you cannot access members of that type. You would need change from a structure to a class that must implement IComparable so that you can use CompareTo between the item you pass in and the array you are passing in.
Though it's not entirely clear what you are trying to do within your method so I'm guessing by the name of the method.
You can use reflection to get those fields, but in this case that wouldn't have much meaning. How would you know that the passed type has the field you're looking for? There are other problems with that code as well.
Instead, to do this I would normally create an interface for something like this that had a public ID property, and constrain my input to the function to implement that interface, or as others mentioned use a built-in feature in the clr.
But that may be ahead of where your students are. If you just want an example of a generic function, my suggestion is to show them a type-safe implementation of the old vb imediate if function:
Public Function IIf(Of T)(ByVal Expression As Boolean, ByVal TruePart As T, ByVal FalsePart As T) AS T
If Expression Then Return TruePart Else Return FalsePart
End Function
Note that this is obsolete, too, as in VS2008 and beyond you can use the new If operator instead, which will work better with type inference and won't try to evaluate the expression that isn't returned.