I am trying to use a LINQ query to grab some data from a database, and since I am grabbing just one column of data I want to store it within a string list. This is the code I have.
Dim POList As New List(Of String)
Using dbContext As New DBLINQDataContext
Dim query = (From o In dbContext.Orders
Where o.Order_Number.StartsWith(JobNumber)
Select o.Order_Number)
POList = query.ToList()
End Using
MessageBox.Show(POList.ToString())
When I run this the data in the MessageBox is
System.Collections.Generic.List`1[System.String]
There is no table data, even though I know there are actual data points for me to be getting :\
POList.ToString() will display the name of the object type.
You can use string.Join(",", POList.ToString()).
You can also define an extension method StringJoin() to show your list as string if you are going to use it frequently.
Here is an extension method that you can use:
public static StringExtensions
{
public static string StringJoin(this IEnumerable<string> strings, string seperator)
{
if (strings == null) return null;
return string.Join(seperator, strings);
}
}
Since this was a vb.net question, I translated #vendettamit 's excellent answer for the benifit of future vb readers.
Public Module StringExtensions
<Extension()>
Public Function StringJoin(MyStrings As IEnumerable(Of String), separator As String) As String
If MyStrings Is Nothing Then
Return Nothing
Else
Return String.Join(separator, MyStrings)
End If
End Function
End Module
To use the extension...
Dim l As New List(Of String) From {"Mathew", "Mark", "Luke", "John"}
Dim s As String = l.StringJoin(", ")
Debug.Print(s)
Related
I'd like to convert an unknown basic structure to an Object (no type here).
I'm building a library that will be used by many users to extract data from my system but don't want to do a new function for everyone of them. They have to know what will be the result.
In vb, it is possible to create an Object with some properties and use it as it is a regular Class like so:
Dim myObj as New With { .name = "Matt", .age = "28" }
MsgBox( myObj.name & " is now " & myObj.age & " years old.")
So far, so good.
Next step : my user will give me some instructions that I need to extract data from various DBs, and I've no idea of what the result will be.
What I know after the execution is a list of String containing the columns of the result set and, of course a (set of) rows.
And here is the problem of course
My function (for a single row) so far:
Public Function GetData(ByVal instructions as String) as Object ' User is supposed to know what will be inside, instructions is as XML describing DB, table, query, ...
' Do what is needed to retrieve data
' Here I have a variable cols As List(Of String) ' e.g. ("BP", "NAME", "VAT")
Dim o As New With ???
Return o
End Function
What I've tried: build a fake JSon on the fly, and try to Deserialize to Object.
But even if it seems to work, I (and the user) can't access the property as in my top piece of code like:
MsgBox(o.BP)
I know that I could do
Public Function GetData(Of T As {New})(ByVal instructions as String) As T
Dim o As T
' Use some Reflexion to TryInvokeMember of T
Return o
End Function
But I wanted to remove the hassle to create a class to use my code.
Plus, My librairy will be use in a webservice and the class of the user is then unknown.
One approach could be - to use Dictionary(Of String, Object)
Public Function GetData(instructions as String) As Dictionary(Of String, Object)
Dim data = ' Load data
Dim columns As String() = { "BP", "NAME", "VAT" }
Return columns.ToDictionary(
Function(column) column,
Function(column) data.GetByColumnName(column)
)
End Function
` Usage
Dim result = GetDate("instructions: ['BP', 'NAME']")
' Because user knows it is Integer
Dim bpValue = DirectCast(result.Item("BP"), Integer)
Thanks to #GSerg, #Fabio and a few other searches about ExpandoObject, I did it !
Imports System.Dynamic
Dim o As Object = New ExpandoObject()
For Each col In cols
DirectCast(o, IDictionary(Of String, Object)).Add(col, row.GetString(col))
Next
In my original code I have a list object containing 2 columns, Word and Percent. I sort the list but only want to return the list containing just the Word
Here is some example code broken down into something simple:
Public Function SortMyWords() as list(of string)
Dim Words As WordsToSort
Dim ListofWords As New List(Of WordsToSort)
Words.Word = "John"
Words.Percent = "10"
ListofWords.Add(Words)
Words.Word = "Robert"
Words.Percent = "1"
ListofWords.Add(Words)
ListofWords = ListofWords.OrderBy(Function(x) x.Percent).ToList()
End Sub
Public Structure WordsToSort
Public Word As String
Public Percent As String
Public Sub New(ByVal _word As String, ByVal _percent As String)
Word = _word
Percent = _percent
End Sub
End Structure
At the end of the SortMyWords function, I want to return just the Word column back as a list, I'm not sure if I can do this direct - i.e.
Return Listofwords(column Word) or whether I need to copy my ListofWords into a new list, just containing the Column Word - something like this (which doesn't work)
Dim Newlist As New List(Of String)
Newlist.AddRange(ListofWords(Words.Word))
Return NewList
Any suggestions on whether I should do this completely differently (and better) would be really appreciated as I am trying to get my head around objects and although I use them all the time, I'm new to structures and list objects.
Thanks for any help, this has been driving me crazy for an hour now.
I think you're close. Try:
ListOfWords
.OrderBy(Function(x) x.Percent)
.Select(Function(x) x.Word)
.ToList()
If you prefer, you can also use the LINQ syntax:
(from w in ListOfWords
orderby w.Percent ascending
select w.Word).ToList()
Note that the return type is a List(Of String) and not a List(Of WordsToSort) anymore. So you cannot assign it back to the variable ListOfWords again like you do in your sample code.
I have a Dictionary object declared as var as Dictionary(of String, String).
I am trying to utilize the LINQ extensions available to the Generic Collection but am only getting the non-extension methods.
I need to turn the Dictionary collection into a string with the following pattern: key1=val1, key2=val2, ..., keyn=valn
Thought at first doing a foreach loop would hit the spot except the fact that i am programmers-block.
What i have so far, but doubt its the best logic pattern for producing this:
Public Overrides Function ToString() As String
Dim ret As String = ""
For Each kv As KeyValuePair(Of String, String) In Me._set
If ret <> String.Empty Then
ret &= ", "
End If
ret &= String.Format("{0}={1}", kv.Key, kv.Value)
Next
Return ret
End Function
And for some reason even though i have imported the System.Core & System.Linq libraries into the project none of the extended LINQ extensions are showing up in my dev-env intellisense. So for now, unless someone could help me get the LINQ extensions to show up in Intellisense, they are out of the question.
Found the problem with the LINQ extensions not showing up, so they are back on the table ;)
I would have written the whole method block with Linq like this (sorry for the C#-vb.net soup...)
c-sharp
return String.Join(",",Me._set.Select(kvp=>String.Format("{0}={1}",kvp.Key, kvp.Value).ToArray());
Also, I don't really know what _set is. Maybe you'll have to cast :
c-sharp:
return String.Join(",", Me._set.Cast<KeyValuePair<String,String>>().Select(kvp=>String.Format("{0}={1}",kvp.Key, kvp.Value).ToArray());
vb.net:
return String.Join(", ", Me.Select(Function(kvp) String.Format("{0}={1}", kvp.Key, kvp.Value)).ToArray())
Hope this will help,
As far as your non-LINQ loop goes, I would recommend doing it like this:
Public Overrides Function ToString() As String
Dim items As New List(Of String)(_set.Count)
For Each pair As KeyValuePair(Of String, String) In _set
items.Add($"{pair.Key}={pair.Value}"))
Next
Return String.Join(", ", items)
End Function
With LINQ, you could do it like this:
Public Overrides Function ToString() As String
Return String.Join(", ", _set.Select(Function(pair) $"{pair.Key}={pair.Value}"))
End Function
VB.net syntax:
Dim dic As New Dictionary(Of String, String)() From {
{"a", "1"},
{"b", "2"},
{"c", "3"},
{"d", "4"}
}
Dim s As String = String.Join(",", dic.Select(Function(pair) String.Format("{0}={1}", pair.Key, pair.Value)).ToArray())
I am having trouble understanding the difference between these two commands that in my mind should do the same thing. I have posted the entire code below in case anything is unclear.
I have created two functions in class Person, one that returns a list containing first,middle and last names and one that returns a concatenated string of the name. I reference the function that returns the list to concatenate the string with the line below:
FullName = String.Join(" ", Me.Get_NameList())
However, when I call:
Console.WriteLine(Person1.Print_Name())
I get what looks like the list object instead of the string:
System.Collections.Generic.List`1[System.String]
If I change the code to look like this:
Public Function Print_Name()
Dim FullNameList As List(Of String) = Me.Get_NameList()
Dim FullName As String
FullName = String.Join(" ", FullNameList)
Return FullName
End Function
The console prints:
John Q Doe
Why am I getting a different answer by first assigning the list to a variable and then joining it? Does this have something to do with how the list is stored in memory?
Thanks in advance for the help.
Here is the full code:
Imports System
Module Module1
Sub Main()
Dim Person1 As New Person("John", "Q", "Doe")
Console.WriteLine("Get_Name Values")
Dim g1 As List(Of String) = Person1.Get_NameList()
Console.WriteLine(String.Join(" ", g1))
Console.WriteLine("Print_Name Values")
Console.WriteLine(Person1.Print_Name())
End Sub
End Module
Class Person
Private FirstName As String
Private MiddleName As String
Private LastName As String
Public Sub New(ByVal Fn As String, ByVal Mn As String, ByVal Ln As String)
FirstName = Fn
MiddleName = Mn
LastName = Ln
End Sub
Public Function Get_NameList()
Dim NameList As New List(Of String)
NameList.Add(FirstName)
NameList.Add(MiddleName)
NameList.Add(LastName)
Return NameList
End Function
Public Function Print_Name()
'Dim FullNameList As List(Of String) = Me.Get_NameList()
Dim FullName As String
FullName = String.Join(" ", Me.Get_NameList())
Return FullName
End Function
End Class
GetNameList returns an Object (because you don't specify the return type).
So the Join method is getting an object. So the VB.Net is turning the Object into a String() with one element that is Object.ToString(). Sometimes the method, especially if it is an old school VB holdover, would check to see if the object passed was an IEnumerable and just iterate over the Objects in the passed object. But not always. So having Strict and Explicit OFF can lead to very strange and hard to find bugs. Those two things should only be OFF in very specific cases where you want all the flexibility turning them off gives you AND you are ready to deal with the oddities that result.
Change the return type of Get_NameList to List(Of String)
And turn on option Strict ON and Option Explicit On to see your other problems.
if you change this line:
Public Function Get_NameList()
to
Public Function Get_NameList() AS List(Of String)
And this line
Public Function Print_Name()
to
Public Function Print_Name() as string
it will work
Say I have a List(Of Tag) with Tag being an object. One member of Tag, Tag.Description, is a string, and I want to make a comma-separated concatenation of the Description members.
Is there an easier way to do this than to read the Description members into a List(Of String) and then use the Join function?
Thanks!
Try this:
String.Join(", ", tagList.Select(t => t.Description).ToArray());
Sorry, I just read again and saw you're using VS2005; so maybe best way is to create a StringBuilder and concatenate your tag.Description.
Here's a Visual Studio 2005 Solution
Public Function ConcatDescription(ByVal list As List(Of Tag) As String
Dim builder as New StringBuilder
Dim isFirst As Boolean = True
For Each t As Tag in list
If Not isFirst Then
builder.Append(","c)
End If
builder.Append(t.Description)
isFirst = False
Next
Return builder.ToString()
End Function