How do I get the index of an object in a For Each...Next loop? - vb.net

I'm using the following syntax to loop through a list collection:
For Each PropertyActor As JCPropertyActor In MyProperty.PropertyActors
i = IndexOf(PropertyActor)
Next
How do I get the index of the current object within the loop? I'm using IndexOf(PropertyActor) but this seems inefficient as it searches the collection when I already have the object available!

An index doesn't have any meaning to an IEnumerable, which is what the foreach construct uses. That's important because foreach may not enumerate in index order, if your particular collection type implements IEnumerable in an odd way. If you have an object that can be accessed by index and you care about the index during an iteration, then you're better off just using a traditional for loop:
for (int i=0;i<MyProperty.PropertyActors.Length;i++)
{
//...
}

AFAIK since this pulls the object out of the collection, you would have to go back to the collection to find it.
If you need the index, rather than using a for each loop, I would just use a for loop that went through the indices so you know what you have.

It might be easiest to just keep a separate counter:
i = 0
For Each PropertyActor As JCPropertyActor In MyProperty.PropertyActors
...
i = i + 1
Next
As an aside, Python has a convenient way of doing this:
for i, x in enumerate(a):
print "object at index ", i, " is ", x

just initialize an integer variable before entering the loop and iterate it...
Dim i as Integer
For Each PropertyActor As JCPropertyActor In MyProperty.PropertyActors
i++
Next

Add an index variable that you increase yourself for each iteration?

You could use the "FindIndex" method.
MyProperty.PropertyActors.FindIndex(Function(propActor As JCPropertyActor) propActor = JCPropertyActor)
But inside of a for each loop that seems like alot of extra overhead, and seems like the same resulting problem as the "IndexOf" method. I suggest using old fashioned index iteration. This way you have your index and your item.
Dim PropertyActor As JCPropertyActor
For i As Integer = 0 To MyProperty.PropertyActors.Count - 1
PropertyActor = MyProperty.PropertyActors.Item(i)
Next

Related

Are there better ways to split arrays into smaller arrays?

I have a program that will create orders for a bunch of orders. However API has limitation that if I wanna do that I got to do it 10 at a time
If orderList.Count > 10 Then
Dim FirstTwenty = From n In orderList Take (10)
Dim theRest = From n In orderList Skip (10)
Dim result1 = Await internalActualcreateNormalLimitOrderMultiple(FirstTwenty.ToArray)
Dim result2 = Await internalActualcreateNormalLimitOrderMultiple(theRest.ToArray)
Return result1 + result2 'no longer json but we don't really use the resulting json unless for debugging
End If
Basically I want to split {1,2,3,4,5,6,7,8,9,10.11.12,...} into {1,2,3}{4,5,6},{7,8,9},...
And I wonder if I can use linq instead of for each
So I use this recursive function. Get first 10 or twenty and then recursively call the function and so on.
And I look at it and while it's simple, it doesn't seem right. Obviously number of orders won't be big. At most 15. But what about if on day I have 100? I can get like stackoverflow for recursive things.
If only there is a function that can split arrays into array using linq, where, take, and skip that'll be great.
Of course I can do for each but perhaps there is a more elegant way?
Then I wrote another code
Public Shared Function splitArrayIntoSmallerArrays(Of someObject)(arrayOfSomeObject As someObject(), chunkSize As Integer) As List(Of someObject())
Dim output = New List(Of someObject())
Dim newestArray = New List(Of someObject)
For i = 0 To arrayOfSomeObject.Count - 1
newestArray.Add(arrayOfSomeObject(i))
If newestArray.Count = chunkSize Then
output.Add(newestArray.ToArray)
newestArray = New List(Of someObject)
End If
Next
output.Add(newestArray.ToArray)
Return output
End Function
That'll do it in O(n)
But I think it can be done more simply by using linq, seek, and take but I don't know how. Or may be group by.
Any idea?
Your question was not very clear to me, but I believe you have an array with several "objects" inside it, correct? And before that you want to divide this matrix into smaller matrices, correct?
So how about passing this larger matrix to a JSON, creating an object that will be filled in by the smaller values ​​and then transforming this JSON again into objects of the type above, then passing these objects to the smaller array, do you understand?
If you have access to Net 7.0, perhaps you're looking for Enumerable.Chunk?
Splits the elements of a sequence into chunks of size at most size.

Kotlin error "Index Out Of Bounds Exception"

I'm newbie to Kotlin, and new to programming also, so pls be gentle :)
Let's say I have a string (it was optimized to NOT have any duplicated character), i want to compare all characters in that string to the alphabet, which declared as a mutable List of character. I want to delete any character from the alphabet which show up in the string. My code is as below
var alphabet=mutableListOf('a','b','c','d','e','f','g','h','i','j','k','l','m',
'n','o','p','q','r','s','t','u','v','w','x','y','z')
var key="keyword"
println(key)
for (i in key.indices)
{for (j in alphabet.indices)
{if (key[i] == alphabet[j])
alphabet.removeAt(j) // 1. this line have error
//print(alphabet[j]) //2. but this line runs fine
}}}
In above code, I have error at the "alphabet.removeAt(j)" command, so I try another command to print out the characters instead of delete them, and it runs fine. I read some articles and I know this error related to the invalid index, but I used the "indices" key and I think it's pretty safe. Pls help
It is safe to iterate using alphabet.indices, but it is not safe to iterate over a collection while modifying it. Note that indices returned indices for a full alphabet, but then you removed some items from it, making it shorter, so indices are no longer valid.
You don't need to iterate over a collection to find an item to remove. You can just do:
alphabet.remove(key[i])
But honestly, you don't need to do anything of this. Your problem is really a subtracting of two sets and you can solve it much easier:
('a'..'z').toSet() - "keyword".toSet()
You could simplify that whole loop to just:
alphabet.retainAll{ it !in key })
or
alphabet.retainAll { !key.contains(it) }
or if you want the filtered list to be a new list rather than doing it in-place:
val filtered = alphabet.filter { it !in key }
but I used the "indices" key and I think it's pretty safe
Well, the indices collection is only evaluated once when a loop is entered, not at the start of each iteration. Even if you change the size of alphabet in the inner loop, the inner loop will still loop the same number of times, because it doesn't evaluate alphabet.indices again. It would only do that again on the next iteration of the outer loop, but your code would throw an exception before that point.
Other than decreasing j whenever you remove an item, you can also solve this by
key.forEach(alphabet::remove)

Unable to increment Counter using linq

Hello AllSo i am trying to edit and insert rows into a datatable using linq but i am unable to increment the counter using Linq
Basically what i am trying to do is first edit or the data using Select method and assigning it to variable in my query using let and then using normal Add method to add all the rows into the dt SO my first question is can i directly add all the rows without needing the counter ?
The reason i need counter is what i am trying to do is take one element per iteration using its index for example x(1).....x(n) so for the index i need counter so for counter i created a variable outside the flow and incremented it inside our linq query but it didnt work out.....
The code i have tried
(From roww In DT.AsEnumerable() Let x=DT.AsEnumerable().Select(Function(r) CStr(r("Column1")).Substring(0,3) ).ToArray Select
DT.Clone.Rows.Add(roww.Item("Some Column"),roww.Item("Column1"),x)).CopyToDataTable
(From roww In DT.AsEnumerable() Let x=DT.AsEnumerable().Select(Function(r) CStr(r("Column1")).Substring(0,3) ).ToArray Select
DT.Clone.Rows.Add(roww.Item("Some Column"),roww.Item("Column1"),x(y+1))).CopyToDataTable
Another thing what i was looking to use Expression.Increment Method but i havent used it dont know what exactly it is and whether it can be converted to int
ANy inputs ??
Hello all i did the above question using this query
(From roww In DT.AsEnumerable() Select
DT.Clone.Rows.Add(roww.Item("Some other data"),roww.Item("Column1"),CStr(roww.Item("Column1")).Substring(0,4))).CopyToDataTable
But i still want to know how can i increment counter if any one knows how to do it please let me know.......Even if its in C#'s format ill learn the logic or syntax
Thank you
While your answer is the correct solution to your query, if you had some other type of array not dependent on your original data source, you may need to index into the array in parallel with your data source. While a For..Next would be the best way to handle this, you can emulate the same effect with LINQ using Enumerable.Range and Zip.
The Let statement is translated into a Select that carries the Let variable value along with each row. The Enumerable.Range provides a source of increasing integers you can use to index into an array.
Dim addedDT = (DT.AsEnumerable() _
.Select(Function(roww) New With { Key .x = DT.AsEnumerable.Select(Function(r) CStr(r("Column1")).Substring(0,3)).ToArray, roww }) _
.Zip(Enumerable.Range(0, DT.Rows.Count), Function(xroww, y) DT.Clone.Rows.Add(xroww.roww.Item("Some Column"),xroww.roww.Item("Column1"),xroww.x(y+1))
).CopyToDataTable
Looking at the Let translation makes it more apparent that the calculation of x occurs once per data source row and is very inefficient. Pulling the constant value out makes for a better version:
Dim x = DT.AsEnumerable.Select(Function(r) CStr(r("Column1")).Substring(0,3)).ToArray
Dim addedDT = (DT.AsEnumerable() _
.Zip(Enumerable.Range(0, DT.Rows.Count), Function(roww, y) DT.Clone.Rows.Add(roww.Item("Some Column"),roww.Item("Column1"),x(y+1))
).CopyToDataTable

VB.NET "For each" versus ".GetUpperBound(0)"

I would like to know what is preferred...
Dim sLines() As String = s.Split(NewLine)
For each:
For Each sLines_item As String In sLines
.GetUpperBound:
For i As Integer = 0 To sLines.GetUpperBound(0)
I have no idea why the "For Each" was introduced for such cases. Until now I have only used .GetUpperBound, and I don't see any PRO for the "For Each".
Thank you
ps: When I use ."GetUpperBound(0)", I do know that I am iterating over the vector.
The "For Each" in contrast sounds like "I don't care in which order the vector is given to me". But that is just personal gusto, I guess.
Short answer: Do not use GetUpperBound(). The only advantage of GetUpperBound() is that it works for multi-dimensional arrays, where Length doesn't work. However, even that usage is outdated since there is Array.GetLength() available that takes the dimension parameter. For all other uses, For i = 0 to Array.Length - 1 is better and probably the fastest option.
It's largely a personal preference.
If you need to alter the elements of the array, you should use For i ... because changing sLines_item will not affect the corresponding array element.
If you need to delete elements of the array, you can iterate For i = ubound(sLines) to 0 step -1 (or the equivalent).
Short answer
You should always use For Each on IEnumerable types unless you have no other choice.
Long answer
Contrary to the popular understanding, For Each is not a syntactic sugar on top of For Next. It will not necessarily iterate over every element of its source. It is a syntactic sugar on top of IEnumerable.GetEnumerator(). For Each will first get an enumerator to its source then loop until it cannot enumerate further. Basically, it will be replaced by the following code. Keep in mind that this is an oversimplification.
' Ask the source for a way to enumerate its content in a forward only manner.
Dim enumerator As IEnumerator = sLines.GetEnumerator()
' Loop until there is no more element in front of us.
While enumerator.Next() Then
' Invoke back the content of the for each block by passing
' the currently enumerated element.
forEachContent.Invoke(enumerator.Current)
End While
The major difference between this and a classical For Next loop is that it does not depend on any length. This fixes two limitations in modern .NET languages. The first one has to do with the Count method. IEnumerable provides a Count method, but the implementation might not be able to keep track of the actual amount of elements it stores. Because of this, calling IEnumerable.Count might cause the source to be iterated over to actually count the amount of element it contains. Moreover, doing this as the end value for traditional For Next loop will cause this process to be done for every element in the loop. This is very slow. Here is an illustration of this process:
For i As Integer = 0 To source.Count() ' This here will cause Count to be
' evaluated for every element in source.
DoSomething(source(i))
Next
The use of For Each fixes this by never requesting the length of the source.
The second limitation it fixes is the lack of a concept for arrays with infinite amount of elements. An example of such cases would be an array containing every digit of PI where each digit is only calculated when you request them. This is where LINQ makes its entrance and really shines because it enables you to write the following code:
Dim piWith10DigitPrecision = From d In InfinitePiSource
Take 10
Dim piWith250DigitPrecision = From d In InfinitePiSource
Take 250
Dim infite2PiSource = From d In InfinitePiSource
Select d * 2
Now, in an infinite source, you cannot depend on a length to iterate over all of its elements. It has an infinite length thus making a traditional For Next loop an infinite loop. This does not change anything for the first two examples I have given with pi because we explicitly provides the amount of elements we want, but it does for the third one. When would you stop iterating? For Each, when combined with Yield (used by the Take operator), makes sure that you never iterate until you actually requests a specific value.
You might have already figured it out by now but these two things means that For Each effectively have no concept of bounds because it simply does not require them. The only use for GetLowerBound and GetUpperBound are for non-zero-indexed arrays. For instance, you might have an array that indexes values from 1 instead of zero. Even then, you only need GetLowerBound and Length. Obviously, this is only if the position of the element in the source actually matters. If it does not, you can still use For Each to iterate over all elements as it is bound agnostic.
Also, as already mentioned, GetLength should be used for zero-indexed multi-dimensional arrays, again, only if the position of the element matters and not just the element itself.

Search arraylist of objects

I have an arraylist of objects, I would like to know the index within the arraylist of the object that contains a certain value, is there a built-in way to do the search?
I know I could simply iterate through the arraylist to find the correct value e.g. :
ReportToFind="6"
For i = 0 To ReportObjList.Count - 1
If ReportObjList.Item(i).ReportCode = ReportToFind Then
ReportName.Text = ReportObjList.Item(i).ReportName ' found it - show name
Exit For
End If
Next
Is the only other solution be to replace this code a binary search?
.Net 1.1
You need to use better data structures in the case that searching through a list is a problem. You can use a binary search for your arraylist in the case that your list is sorted with respect to the value to be searched. In other cases you would be better of using smarter data structures such as a binary tree or a map.
I don't know if .Net 1.1 has it, but you could try the .IndexOf method on your array list.
It looks like you need to index your reportObjectList by reportCode in addition to the item index.
You can do this either in a second parallel list with the reportCode as the index and the itemIndex as the value.