I have tree classes as follows:
Public Class HtmlSection
Property Name As String
Property SubSections As List(Of HtmlSubSection)
End Class
Public Class HtmlSubSection
Property Name As String
Property SelectedSentences As List(Of HtmlSentence)
End Class
Public Class HtmlSentence
Property Sentence As String
Property Position As Integer
End Class
In below method i am searching for all sentences for each subsection belonging to specific section, at the end i sort those records by Position asc. However sometimes positions have to be changed (directly in sentences) because there could be gaps means after i do OrderBy it will be ordered but it could look like this below. Is there any easy way like linq to change that Positions of that sentences to avoid gaps let's say in the method i shown below.
2
5
77
1001
i would like to change positions starting from 0 in our example:
0
1
2
3
Method:
Public Function GetSelectedSentencesOnSectionLevel(section As HtmlSection) As List(Of HtmlSentence)
Dim sentencesList As New List(Of HtmlSentence)
For Each exSection As HtmlSection In _htmlFactory.SectionsList
If exSection.Name = section.Name Then
Dim sentencesList As New List(Of HtmlSentence)
If Not IsNothing(exSection.SubSections) Then
For Each exSubsection As HtmlSubSection In exSection.SubSections
If Not IsNothing(exSubsection.SelectedSentences) Then
For Each exSentence As HtmlSentence In exSubsection.SelectedSentences
sentencesList.Add(exSentence)
Next
End If
Next
End If
End If
Next
'sort sentences by Posiions ascending
sentencesList = sentencesList.OrderBy(Function(x) x.Position).ToList()
Return sentencesList
End Function
EDIT : more code for helpers:
global class:
Public Class HtmlFactory
Property SectionsList As List(Of HtmlSection)
Sub New()
SectionsList = New List(Of HtmlSection)
End Sub
Sub New(pSectionsList As List(Of HtmlSection))
_SectionsList = pSectionsList
End Sub
Public Sub AddSection(section As HtmlSection)
SectionsList.Add(section)
End Sub
....
Here you are a pure LINQ solution.
Dim index As Integer = -1
Dim sectionName As String
Dim allTheSections As List(Of HtmlSection)
Dim sentenceList = allTheSections _
.Where(Function(sect) _
sect.SubSections IsNot Nothing _
AndAlso sect.Name.Equals(sectionName, StringComparison.OrdinalIgnoreCase)) _
.SelectMany(Function(sect) sect.SubSections) _
.Where(Function(subSect) subSect.SelectedSentences IsNot Nothing) _
.SelectMany(Function(subSect) subSect.SelectedSentences) _
.OrderBy(Function(ss) ss.Position) _
.Select(Function(ss)
index += 1
Return New HtmlSentence With {.Position = index, .Sentence = ss.Sentence}
End Function) _
.ToList()
In this example, allTheSections is where you exSection does coming from.
Related
I'm populating a DataGridView from an Excel file, and trying to sort only ONE column of my choice, other columns should remain as-is. How can it be achieved? Should the component be changed to something else, in case it is not possible in DataGridView?
I Created a List of my custom class, and this class will handle the sorting based on my preference (Randomization in this case)
Public Class Mylist
Implements IComparable(Of Mylist)
Private p_name As String
Private r_id As Integer
Public Property Pname() As String 'This will hold the contents of DGV that I want sorted
Get
Return p_name
End Get
Set(value As String)
p_name = value
End Set
End Property
Public Property Rid() As Integer 'This will be the basis of sort
Get
Return r_id
End Get
Set(value As Integer)
r_id = value
End Set
End Property
Private Function IComparable_CompareTo(other As Mylist) As Integer Implements IComparable(Of Mylist).CompareTo
If other Is Nothing Then
Return 1
Else
Return Me.Rid.CompareTo(other.Rid)
End If
End Function
End Class
Then a Button which will sort the contents:
Dim selcol = xlView.CurrentCell.ColumnIndex
Dim rand = New Random()
Dim x As Integer = 0
Dim plist As New List(Of Mylist)
Do While x < xlView.Rows.Count
plist.Add(New Mylist() With {
.Pname = xlView.Rows(x).Cells(selcol).Value,
.Rid = rand.Next()
})
x += 1
Loop
plist.Sort()
x = 0
Do While x < xlView.Rows.Count
xlView.Rows(x).Cells(selcol).Value = plist.ElementAt(x).Pname
x += 1
Loop
xlView.Update()
plist.Clear()
I'm open to any changes to code, as long as it achieves the same result.
Here is the simpler version. Pass the column index will do like Call SortSingleColum(0)
Private Sub SortSingleColumn(x As Integer)
Dim DataCollection As New List(Of String)
For i = 0 To dgvImport.RowCount - 2
DataCollection.Add(dgvImport.Item(x, i).Value)
Next
Dim t As Integer = 0
For Each item As String In DataCollection.OrderBy(Function(z) z.ToString)
dgvImport.Item(x, t).Value = item
t = t + 1
Next
End Sub
I have class sObrazac in which I have
'''<remarks/>
<System.Xml.Serialization.XmlArrayItemAttribute("Primatelji", IsNullable:=false), _
System.Xml.Serialization.XmlArrayItemAttribute("P", IsNullable:=false, NestingLevel:=1)> _
Public Property StranaB() As sPrimateljiP()()
Get
Return Me.stranaBField
End Get
Set
Me.stranaBField = value
End Set
End Property
'''<remarks/>
<System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.6.81.0"), _
System.SerializableAttribute(), _
System.Diagnostics.DebuggerStepThroughAttribute(), _
System.ComponentModel.DesignerCategoryAttribute("code"), _
System.Xml.Serialization.XmlTypeAttribute(AnonymousType:=true, [Namespace]:="http://e-porezna.porezna-uprava.hr/sheme/zahtjevi/ObrazacJOPPD/v1-1")> _
Partial Public Class sPrimateljiP
Private p1Field As Long
Private p2Field As String
Private p3Field As String
Private p4Field As String
.....
'''<remarks/>
Public Property P1() As Long
Get
Return Me.p1Field
End Get
Set
Me.p1Field = value
End Set
End Property
And now I'm setting the object what I have tried
Dim oPrimatelj As New sPrimateljiP
oPrimatelj.P1 = 1
oPrimatelj.P2 = 00019
oPrimatelj.P3 = 00019
oPrimatelj.P4 = 02994650199 ....
After setting that object I tried to push it into list and from it to array
Dim sList As New List(Of sPrimateljiP)
sList.Add(oPrimatelj)
oObrazac.StranaB = sList.ToArray
But as you know it will throw me
Value of type sPrimateljIP() cannot be converted to sPrimateljIP()()
I'm not quite familiar with two dimension arrays and I'm stuck here...
This may clear my question more. What is this element named P.
Note: I can't make schema, I need to adjust code to it.
Ok i found out what solution may be thanks to comment by Chetan. Use jagged array
Push list to jagged array and set it as object
Dim sList As New List(Of sPrimateljiP)
sList.Add(oPrimatelj)
sList.Add(oPrimatelj)
Dim jaggedArray()() As sPrimateljiP = New sPrimateljiP(0)() {sList.ToArray}
oObrazac.StranaB = jaggedArray
I am attempting to parse paragraphs such as the following...
Group 1. Does this or does that. Or Sometimes this. Or that.
Group 2. I do lots of things. But not this. Or that.
Group 3. I do this. I do that. Sometimes this. Sometimes that.
The "Group 1-3" are the org Names, and each following sentence separated by a period is a function.
Code:
Public Sub parseParagraphs(paragraphList As List(Of String))
Dim listOfOrgs As New List(Of EAB_Org)
Dim listOfFuntions As New List(Of String)
Dim orgName As String
For Each item In paragraphList
listOfFuntions.Clear()
Dim words As String() = item.Split(New Char() {"."c}) 'Splits on periods
orgName = words(0) 'Sets the orgName
For index As Integer = 1 To words.Count - 1 'rest of items in list are functions performed
listOfFuntions.Add(words(index))
Next
Dim anOrg As New EAB_Org(orgName, listOfFuntions)
listOfOrgs.Add(anOrg)
Next
End Sub
EAB Class:
Public Class EAB_Org
Dim orgName As String
Dim listOfTasks As List(Of String)
Public Sub New(theOrgName As String, theListOfTasks As List(Of String))
orgName = theOrgName
listOfTasks = theListOfTasks
End Sub
Public Function getOrgName()
Return orgName
End Function
Public Function getListOfTasks()
Return listOfTasks
End Function
End Class
For some reason, when I print out the contents of listOfOrgs, all the org names are correct, but the functions are all of the same and always the last set of functions read in.
Code I use to print:
Public Sub writeExcel(listOfOrgs As List(Of EAB_Org))
For Each anItem In listOfOrgs
Console.WriteLine(anItem.getOrgName)
For Each anotherItem In anItem.getListOfTasks
Console.WriteLine(anotherItem)
Next
Next
End Sub
Output Looks Like:
Group 1
I do this. I do that. Sometimes this. Sometimes that.
Group 2
I do this. I do that. Sometimes this. Sometimes that.
Group 3
I do this. I do that. Sometimes this. Sometimes that.
The problem is that in the constructor for EAB_Org, theListOfTasks is just a pointer to listOfFuntions (which you keep modifying) in the parseParagraphs Sub. In the constructor, you will need to create a new List(Of String) and copy the values from theListOfTasks into it.
Change the constructor to the following:
Public Sub New(theOrgName As String, theListOfTasks As List(Of String))
orgName = theOrgName
listOfTasks = New List(Of String)
For Each item As String In theListOfTasks
listOfTasks.Add(item)
Next
End Sub
I have the following class :
Public Class titlesclass
Public Property Link As String
Public Property Title As String
Public Function Clear()
Link.Distinct().ToArray()
Title.Distinct().ToArray()
End Function
End Class
And the following code :
For Each title As Match In (New Regex(pattern).Matches(content)) 'Since you are only pulling a few strings, I thought a regex would be better.
Dim letitre As New titlesclass
letitre.Link = title.Groups("Data").Value
letitre.Title = title.Groups("Dataa").Value
lestitres.Add(letitre)
'tempTitles2.Add(title.Groups("Dataa").Value)
Next
I tried to delete the duplicated strings using the simple way
Dim titles2 = lestitres.Distinct().ToArray()
And calling the class function :
lestitres.Clear()
But the both propositions didn't work , i know that i'm missing something very simple but still can't find what it is
Easier to use a class that already implements IComparable:
Dim query = From title In Regex.Matches(content, pattern).Cast(Of Match)
Select Tuple.Create(title.Groups("Data").Value, title.Groups("Dataa").Value)
For Each letitre In query.Distinct
Debug.Print(letitre.Item1 & ", " & letitre.Item2)
Next
or Anonymous Types:
Dim query = From title In Regex.Matches(content, pattern).Cast(Of Match)
Select New With {Key .Link = title.Groups("Data").Value,
Key .Title = title.Groups("Dataa").Value}
For Each letitre In query.Distinct
Debug.Print(letitre.Link & ", " & letitre.Title)
Next
Ok, Since I notice you are using a ClassHere is one option you can do in order to not add duplicate items to your List within a class.I'm using a console Application to write this example, it shouldn't be too hard to understand and convert to a Windows Form Application if need be.
Module Module1
Sub Main()
Dim titlesClass = New Titles_Class()
titlesClass.addNewTitle("myTitle") ''adds successfully
titlesClass.addNewTitle("myTitle") '' doesn't add
End Sub
Public Class Titles_Class
Private Property Title() As String
Private Property TitleArray() As List(Of String)
Public Sub New()
TitleArray = New List(Of String)()
End Sub
Public Sub addNewTitle(title As String)
Dim added = False
If Not taken(title) Then
Me.TitleArray.Add(title)
added = True
End If
Console.WriteLine(String.Format("{0}", If(added, $"{title} has been added", $"{title} already exists")))
End Sub
Private Function taken(item As String) As Boolean
Dim foundItem As Boolean = False
If Not String.IsNullOrEmpty(item) Then
foundItem = Me.TitleArray.Any(Function(c) -1 < c.IndexOf(item))
End If
Return foundItem
End Function
End Class
End Module
Another option would be to use a HashSet, It will never add a duplicate item, so even if you add an item with the same value, it wont add it and wont throw an error
Sub Main()
Dim titlesClass = New HashSet(Of String)
titlesClass.Add("myTitle") ''adds successfully
titlesClass.Add("myTitle") '' doesn't add
For Each title As String In titlesClass
Console.WriteLine(title)
Next
End Sub
With all of that aside, have you thought about using a Dictionary so that you could have the title as the key and the link as the value, that would be another way you could not have a list (dictionary) contain duplicate items
I am trying to create a dictionary from a list. I am trying to filter the list such that it contains the id that I am adding as a key to the dictionary. So dictionary would be Key, List - with id as Key.
I have no idea why the following won't work - although the rawlist contains ids, filteredlist is empty. I am checking the value within the loop. Fresh set of eyes please?
resultList is dictionary(string, List)
For Each c As String In listIds
Dim filteredlist = rawList.Where(Function(x) x.id.Trim().Contains(c.Trim())).ToList()
resultList.Add(c,filteredlist)
Next
I need the filtered list. I have tried Contains, Equals and "="
i.e.
Dim filteredlist = rawList.Where(Function(x) x.id.Trim().Equals(c.Trim())).ToList()
and
Dim filteredlist = rawList.Where(Function(x) x.id.Trim() = (c.Trim())).ToList()
Please look into it thanks!
Looks like you have it backwards. Typically you have a list for looking for something first and not iterate through that list which IMHO takes longer.
Filter Linq Child Collection by another List/Array
Public Class POC
Public Property Id As Integer
Public Property Desc As String
Public Property Orders As List(Of Order)
End Class
Public Class Order
Public Property Id As Integer
Public Property Desc As String
End Class
Private Shared Function GetOrders(numberOfOrders As Integer) As List(Of Order)
Dim orders = New List(Of Order)()
For i As Integer = 1 To numberOfOrders
orders.Add(New Order() With { .Id = i, .Desc = "{i} Order" })
Next
Return orders
End Function
Private Shared Function GetPOCOsAndOrders() As List(Of POC)
Return New List(Of POC)() From { _
New POC() With { .Id = 1, .Desc = "John", .Orders = GetOrders(1) },
New POC() With { .Id = 2, .Desc = "Jane", .Orders = GetOrders(2) },
New POC() With { .Id = 3, .Desc = "Joey", .Orders = GetOrders(3) }
End Function
Private Shared Sub Main(args As String())
Dim orders = New List(Of Integer)() From { 2, 3 }
Dim items = GetPOCOsAndOrders()
Dim peopleAndOrdersWhereOrderNumberIsGreaterThanTwo = items.Where(Function(x) x.Orders.Any(Function(y) orders.Contains(y.Id)))
'I should only get the last two people out of three and their orders
peopleAndOrdersWhereOrderNumberIsGreaterThanTwo.ToList().ForEach(Function(x) Console.WriteLine("{x.Id} {x.Desc} {x.Orders.Count}"))
Console.ReadLine()
End Sub
There are many silght variations possible with the limited information you have given us, but a working example is:
Option Infer On
Option Strict On
Module Module1
Public Class datum
Property Id As String
Property Name As String
Public Sub New()
' empty constructor
End Sub
Public Sub New(Id As String, Name As String)
Me.Id = Id
Me.Name = Name
End Sub
End Class
Sub Main()
' sample data...
Dim rawData = New List(Of datum)
rawData.Add(New datum("cat", "Lulu"))
rawData.Add(New datum("cat", "Uschi"))
rawData.Add(New datum("snake", "Sid"))
rawData.Add(New datum("fox", "Reynard"))
rawData.Add(New datum("mouse", "Jerry"))
' what to look for:
Dim listIds As New List(Of String) From {"CAT", "mouse", "ELK"}
' somewhere to store the results:
Dim dict As New Dictionary(Of String, List(Of String))
' filter by what to look for:
For Each c In listIds
Dim foundItems = rawData.Where(Function(x) String.Compare(x.Id, c, StringComparison.OrdinalIgnoreCase) = 0)
' only add items to the dictionary if the Id was found:
If foundItems.Count() > 0 Then
' use the case of the id from the raw data:
dict.Add(foundItems(0).Id, foundItems.Select(Function(f) f.Name).ToList())
End If
' alternative which includes dictionary entries where the Id was not found:
'dict.Add(If(foundItems.Count = 0, c, foundItems(0).Id), foundItems.Select(Function(f) f.Name).ToList())
Next
' show the dictionary contents:
For Each kvp In dict
Console.WriteLine(kvp.Key & ": " & String.Join(", ", kvp.Value))
Next
Console.ReadLine()
End Sub
End Module
Output:
cat: Lulu, Uschi
mouse: Jerry
I have included commented-out code for some variations you may want.