Unable to increment Counter using linq - vb.net

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

Related

Need Help Creating Custom Sorter On ObjectListView

Ok, I'm totally at a loss with this....
I think I have looked at every example and every code snippet around and still can't work out how to implement a custom sorter on my ObjectListView.
My primary column (column 0) contains numbers only (as a string) but is sorting all items by alphanumeric instead of numeric, meaning that it is doing something like this:
1
11
111
2
22
etc.
I am trying to find a relatively simple example of how to modify my ObjectListView to sort column 0 when it first loads, but I'm struggling.
I have converted over a custom class called ColumnSorter (from CodeProject) into VB and I'm calling the following delegate:
lvwColumnSorter = New CustomLVSorter.CustomLVSorter()
lsv_OpenTickets.CustomSorter = Sub(column As OLVColumn, order As SortOrder)
lvwColumnSorter.ColumnToSort = Ticket_Status.Index
lvwColumnSorter._SortModifier = CustomLVSorter.CustomLVSorter.SortModifiers.SortByText
lvwColumnSorter.OrderOfSort = SortOrder.Ascending
lsv_OpenTickets.ListViewItemSorter = lvwColumnSorter
End Sub
I get no errors, but I also get no change.
Any help would be greatly appreciated.
Well, are you sure you have looked at every example? I think there are a lot of resources on this one.
When you're using a list, datagridview, or any main form, you can adjust it to use a custom sorter. You create a custom IComparer, i.e. the definition of how you sort something. It can be as simple as converting the string (like yours) to an int with CInt() and returning -1 or +1 if it is greater or less than the last value. This is very common.
If you need help on the basics of how to do it, of course there are always the microsoft links that give you the basics such as Custom Sort I Comparer. But there is a stack flow that also follow your problem here: Custom sort C#
It's in C#, but there are many converters on that around here.
But the easiest way to get around it? Convert your string list into a integer list. Then it will sort perfectly.

Find a Value in Two Dimensional Array on VB.NET

I declared my Array:
Dim invoice_discountitems(100, 100) As String
Set Values into array:
For i As Int16 = 0 To data_set.Tables("discount_items").Rows.Count - 1
invoice_discountitems(i, 1) = data_set.Tables("discount_items").Rows(0).Item("item_code")
invoice_discountitems(i, 2) = data_set.Tables("discount_items").Rows(0).Item("discountitem_average")
Next
Now I try to find a single value:
Dim res As String
res = Array.IndexOf(invoice_discountitems, "FO1506")
MsgBox(res)
But, I get this error :(
"Only single dimension arrays are supported here"
This is a fundamentally wrong approach - for a number of reasons
You're treating ALL the data points as Strings
You're not taking advantage of DB optimisations like indices
You're loading data into memory that you're never going to use (at least int he example)
The Nicest way to do it would be with Linq-To-Entities:
Dim Record = MyDBContext.Discount_Items.Where(function(x) x.ItemCode = "FO1506").Single
Console.WriteLine(Record.discountitem_average);
If you're stuck with your current Data Access Layer, you need to modify the SQL being executed to only return the information you're interested in. Without more information, I can't provide decent example code but you want the SQL to end up looking like this...
SELECT itemcode,
discountitem_average,
[Other fields],
FROM MyDatabase.M
EDIT: To Clarify, there are a number of ways to access data in a database. The one I prefer is LINQ-To-Entities (Have a look through this tutorial).
In short, you add a new Item to your project and point it at your database. This becomes your "Database Context" - it represents the database and that's how you run queries.
Project -> Add -> New Item...
Select ADO.Net Entity Data Model (Linq-To-Entities is almost Identical to Linq-To-Sql but more recent and better supported - use Entities until you know the difference)
Call it something like MyDBContext
When prompted, choose "Generate From Database" and point it at your database.
It's worth noting that the designer takes advantage of information in the database like Foreign Key Constraints - So the better your database is designed, the better the model it will create.
Then, you refer to it in code as shown in my first example.
First of all IndexOf return int as index!
To get the index of string
Try:
Dim i As int
Dim j As int
i = Array.IndexOf(invoice_discountitems.OfType(Of String)().ToArray(), "FO1506")
j = i MOD 100
i= i/100
MsgBox(i+" "+j)
(I use c# but I think it's not different)

How Do I step through an IList one field at a time?

I'm using the Dynamic LINQ library code sample to dynamically return some data. The number of columns I'm returning is variable depending on user input. I'm enumerating the IQueryable into an IList.
What I need to do is step through the Ilist one field at a time. I can get one row at a time by iterating through the IList's rows but I can't for the life of me pull one field out of the collection.
For example, here I'm returning two columns (hard coded for testing but in prod it will be variable depending on what fields the user chooses):
Dim Dynq = dc.dt _
.Where("RUN_ID = """ & runNumber & """ and Upper_Pressure > 95") _
.OrderBy("Upper_Pressure") _
.Select(" new (Run_ID,Process)")
Dim something = DirectCast(Activator.CreateInstance(GetType(List(Of )).MakeGenericType(Dynq.ElementType), Dynq), IList)
Now I can pull a field out of the Ilist if I know the column name with something like:
something.Run_ID.ToString
but I wont know the columns I'm using until runtime and dynamically inserting it in a variable that's set at runtime doesn't work.
So in Summary I have a Ilist that looks something like this
1 | Auto
2 | Auto
3 | Manual
4 | Manual
and I'd like a way to return
1
and then return
Auto
and then
2
etc...
I would greatly appreciate the help of those more learned than I in this.
Your question is a little confusing, but I think you want to flatten your return set to return specific columns as elements in order by column then row...
One method, you could use is the SelectMany operator.
For example (sorry in C# as my brain is turning one-tracked!):
// Find flattened list of some explicitly specified property values...
var flattened = something.SelectMany(e => new [] { e.Run_ID.ToString(), e.Process.ToString() });
Not sure if that's what your after, but it could be a step in the right direction.

Do you choose Linq over Forloops?

Given a datatable containing two columns like this:
Private Function CreateDataTable() As DataTable
Dim customerTable As New DataTable("Customers")
customerTable.Columns.Add(New DataColumn("Id", GetType(System.Int32)))
customerTable.Columns.Add(New DataColumn("Name", GetType(System.String)))
Dim row1 = customerTable.NewRow()
row1.Item("Id") = 1
row1.Item("Name") = "Customer 1"
customerTable.Rows.Add(row1)
Dim row2 = customerTable.NewRow()
row2.Item("Id") = 2
row2.Item("Name") = "Customer 2"
customerTable.Rows.Add(row2)
Dim row3 = customerTable.NewRow()
row3.Item("Id") = 3
row3.Item("Name") = "Customer 3"
customerTable.Rows.Add(row3)
Return customerTable
End Function
Would you use this snippet to retrieve a List(Of Integer) containing all Id's:
Dim table = CreateDataTable()
Dim list1 As New List(Of Integer)
For i As Integer = 0 To table.Rows.Count - 1
list1.Add(CType(table.Rows(i)("Id"), Integer))
Next
Or rather this one:
Dim list2 = (From r In table.AsEnumerable _
Select r.Field(Of Integer)("Id")).ToList()
This is not a question about whether to type cast the Id column to Integer by using .Field(Of Integer), CType, CInt, DirectCast or whatever but generally about whether or not you choose Linq over forloops as the subject implies.
For those who are interested: I ran some iterations with both versions which resulted in the following performance graph:
graph http://dnlmpq.blu.livefilestore.com/y1pOeqhqQ5neNRMs8YpLRlb_l8IS_sQYswJkg17q8i1K3SjTjgsE4O97Re_idshf2BxhpGdgHTD2aWNKjyVKWrQmB0J1FffQoWh/analysis.png?psid=1
The vertical axis shows the milliseconds it took the code to convert the rows' ids into a generic list with the number of rows shown on the horizontal axis. The blue line resulted from the imperative approach (forloop), the red line from the declarative code (linq).
Whatever way you generally choose: Why do you go that way and not the other?
Whenever possible I favor the declarative way of programming instead of imperative. When you use a declarative approach the CLR can optimize the code based on the characteristics of the machine. For example if it has multiple cores it could parallelize the execution while if you use an imperative for loop you are basically locking this possibility. Today maybe there's no big difference but I think that in the future more and more extensions like PLINQ will appear allowing better optimization.
I avoid linq unless it helps readability a lot, because it completely destroys edit-and-continue.
When they fix that, I will probably start using it more, because I do like the syntax a lot for some things.
For almost everything I've done I've come to the conclusion that LINQ is optimized enough. If I handcrafted a for loop it would have better performance, but in the grand scheme of things we are usually talking milliseconds. Since I rarely have a situation where those milliseconds will make any kind of impact, I find it's much more important to have readable code with clear intentions. I would much rather have a call that is 50ms slower than have someone come along and break it altogether!
Resharper has a cool feature that will flag and convert loops into Linq expressions. I will flip it to the Linq version and see if that hurts or helps readability. If the Linq expression more clearly communicates the intent of the code, I will go with that. If the Linq expression is unreadable, I will flip back to the foreach version.
Most of the performance issues don't really compare with readability for me.
Clarity trumps cleverness.
In the above example, I would go with the the Linq version since it clearly explains the intent and also locks out people accidently adding side effects in the loop.
I recently found myself wondering whether I've been totally spoiled by LINQ. Yes, I now use it all the time to pick all sort of things out from all sort of collections.
I started to, but found out in some cases, I saved time by using this approach:
for (var i = 0, len = list.Count; i < len; i++) { .. }
Not necessarily in all cases, but some. Most extension methods use the foreach approach of querying.
I try to follow these rules:
Whenever I'm just querying (filtering, projecting, ...) collections, use LINQ.
As soon as I'm actually 'doing' something with the result (i.e, introduce side effects), I'll use a for loop.
So in this example, I'll use LINQ.
Also, I always try to split up the 'query definition' from the 'query evaluation':
Dim query = From r In table.AsEnumerable()
Select r.Field(Of Integer)("Id")
Dim result = query.ToList()
This makes it clear when that (in this case in-memory) query will be evaluated.

QTP, access to QC field by label

I want to update a custom user field in QC using the Label of field instead of the name
At the moment we are doing it this way
Set currentRun = QCUtil.CurrentRun
currentRun.Field("RN_USER_03") = 1
currentRun.Post
But I would like to do it this way
Set currentRun = QCUtil.CurrentRun
currentRun.Field("Data Rows Passed") = 4
currentRun.Post
But I can't find the method to do it with.
Any Ideas?
Implying all labels are unique (which I doubt..):
You could create a function which accepts a label, searches in QC's tables that define customized fields for the correct field definition, and returns the field name. Then use the function's result value as the indexed property's index.
Suppose that function would be called "GetNameOfLabel", then the Caller's code would look like:
Set currentRun = QCUtil.CurrentRun
currentRun.Field(GetNameOfLabel ("Data Rows Passed")) = 1
currentRun.Post
Of course, the function would not really be trivial, but easy enough after some digging in the QC data model and finding an efficient way to fetch the name from the DB via SQL.
Or, the function could look up the name in an array, or a dictionary, then you would have to maintain that dictionary, but you would not have to go to the database for each lookup.
Disadventages:
Scripts with the wrong label might be harder to be debug
If labels are not unique, it might be real "fun" to debug
If looking up on the DB:
All scripts slow down if you don't cache, or pre-load, SQL query results for those lookups;
complexity, as you have to do the right SQL query, and you depend on QC's data model in a quite peculiar way (usually a horror when you're upgrading)
If looking up in an array, or dictionary:
You either must maintain its initialization (bet other admin guys adding a cust field will forget that easily), or must "load" it from QC's table (which is a bit like the SQL solution above, and has the same downsides).
I'd go with the array/dictionary-initialized-from-db-idea. Or, if you can live with the constant idea already presented, that one is a good bet. Considering that there is no session-independent scope in QCs customizing scripts, the SQL access idea might really kill performance because it would have to be executed for every new user session. Which is why I, too, +1'd the constant idea.
Look at this:
Dim gFieldLabelToNameDICT: Set gFieldLabelToNameDICT = CreateObject("Scripting.Dictionary")
gFieldLabelToNameDICT.CompareMode = vbTextCompare
Function GetNameOfLabel (strFieldLabel)
' If it doesn't exist yet in fieldLabelToName dict -> search it using TDC and add it to the list to improve performance
If Not gFieldLabelToNameDICT.Exists(strFieldLabel) Then
Dim testSetFields As List
Dim testSetFields: Set testSetFields = QCUtil.QCConnection.Customization.Fields.Fields("RUN")
For Each aField in testSetFields
If aField.UserLabel = strFieldLabel Then
gFieldLabelToNameDICT.Item(strFieldLabel) = aField.ColumnName
End If
Next aField
End If
GetNameOfLabel = gFieldLabelToNameDICT.Item(strFieldLabel)
End Function
Maybe you shall want to add some more error handling, such us considering the case that the label is not found.