String 排序重复字符串的最快方法是什么
我正在开发一个应用程序,它以各种方式处理字符串。其中之一是在合并文件时删除任何重复项。 我已尝试使用此选项:String 排序重复字符串的最快方法是什么,string,vb.net,duplicates,String,Vb.net,Duplicates,我正在开发一个应用程序,它以各种方式处理字符串。其中之一是在合并文件时删除任何重复项。 我已尝试使用此选项: Private Sub run() For Each filePath As String In ListBox1.Items For Each Line In IO.File.ReadAllLines(filePath) Dim founds() As String = Line.Split(":") Dim ha
Private Sub run()
For Each filePath As String In ListBox1.Items
For Each Line In IO.File.ReadAllLines(filePath)
Dim founds() As String = Line.Split(":")
Dim hash As String = founds(0)
Dim word As String = founds(1)
foundList.Add(word)
Dim result As List(Of String) = foundList.Distinct().ToList
Label1.Text = result.Count
For Each addstring In result
ListBox2.Items.Add(addstring)
Next
Next
Next
End Sub
Distinct在这种方式下速度非常慢,因此我尝试使用:
Private Sub run()
For Each filePath As String In ListBox1.Items
For Each Line In IO.File.ReadAllLines(filePath)
Dim founds() As String = Line.Split(":")
Dim hash As String = founds(0)
Dim word As String = founds(1)
If Not foundList.Contains(word) Then
foundList.Add(word)
Label1.Text = foundList.Count
End If
Next
Next
For Each found In foundList
ListBox2.Items.Add(found)
Next
End Sub
这要快得多,但是执行速度仍然比不使用OpenCL或类似工具时要慢。我可以用C#写,如果有什么不同的东西,除了这个在.NET中。
有人能提出一种更快或更有效的方法吗?
不可能是这样,我肯定遗漏了什么。使用哈希集(字符串)
初始化后,HashSet
将包含唯一值。您可以使用
HashSet(Of T).Add(value)
方法-如果值被添加到集合中,则返回true
,如果值已经存在于集合中,则返回false
Dim isAdded As Boolean = uniqueLines.Add("someValue")
If isAdded Then
' Do something if added
Else
' Do something if already exists
End if
HashSet
have-methodContains
哪个算法是O(1)-使用固定数量的运算,例如List。Contains
方法将迭代整个列表,直到找到给定的值(O(N)-运算量等于值情况下的项目数量)
因此,您的函数可以按如下方式重新编写
Private Sub run()
' get data
Dim allItems = ListBox1.Items.
SelectMany(Function(path) IO.File.ReadAllLines(path)).
SelectMany(Function(line) Line.Split(":"))
Dim uniqueItems = New HashSet(Of String)(allItems)
' update controls
Label1.Text = uniqueItems.Count.ToString()
ListBox2.Items.AddRange(uniqueItems.ToArray())
End Sub
请注意,使用
.AddRange
方法将项目添加到列表框2
。此方法将在一次操作中添加项,并仅重新绘制控件一次。当你一个接一个地添加项目时(使用.Add
方法),你可以控制为每个添加的项目重新绘制自己,这对于大量的项目来说可能是“沉重的”。Fabio在我完成之前得到了明显的答案。我已经介绍了更多细节,但请跳到底部了解另一个想法
明显的速度问题在于字符串比较:
If Not foundList.Contains(word) Then
比较字符串是一个相当昂贵的操作,在这里,您将字符串与其他字符串的连续较大列表进行比较。对于一个简短的列表,这可能是好的,但当你处理大的列表时,它会慢一些
更好的选择是将每个字符串散列一次,然后比较散列。需要处理一些技巧,但是当大量数据是唯一的并且散列函数很好时,速度会有很大的提高
在.NET中,该类实现了基于哈希的存储和查找
作为一个集合,HashSet
将只保存任何特定值中的一个,用于处理复制问题。它不保证保留其内容的顺序,但在实践中,如果您只添加而从不删除项目,则顺序将被保留
由于散列值在内部的存储和索引方式,在散列集中的查找速度非常快。测试以查看集合中是否存在值几乎不受列表中项目数的影响。通过一个简单的测试(100000000次查找),我在1000到1000000个字符串的列表中得到大约50ns的查找时间
出于您的目的,用法类似于(在C中):
(对不起,VB不是我的母语。)
问题是,这真的会加快速度吗?你需要自己做一些测试,但我怀疑答案可能是:不多
是的,它比使用Distinct
和ToArray
获取排序值数组更快。通过我的简单测试,速度几乎是原来的两倍~对于数组中100万个不同的36个字符的字符串(是的,它们是GUID),使用180ms到275ms。增幅不大。YMMV,但如果操作所花费的时间远远超过此值,则Distinct
可能不是您最大的问题
做一些分析,找出真正的痛点。我怀疑您会发现ListBox2
设置了Sorted
标志。请尝试以下操作(抱歉,请在C#中重试):
Private子运行()
{
Dim items=ListBox1.items.Of类型(字符串)()。
选择many(函数(fn)File.ReadAllLines(fn))。
选择(功能(i)i.Split(“:”c)(1))
Dim hash=HashSet(项目)
ListBox2.Items.Clear()
Dim sorted=ListBox2.已排序
ListBox2.Sorted=false
ListBox2.Items.AddRange(hash.ToArray())
ListBox2.Sorted=已排序
}
如果这要快得多,那么问题不在Distinct
中,而是在插入时排序,它的速度非常慢,几乎总是排序列表的最差选项
如果不是,则问题可能是在使用Distinct
并添加它们之前获取所有值(最慢的部分仍在更新控件):
Distinct()
很慢,因为您对每个文件中的每一行都调用它。相反,建立您的foundList
,然后在其上调用Distinct()
。同样,在每个文件的每一行填充列表框。正如你所能想象的,这对性能来说是可怕的。仅填充列表一次。。在你有了明确的清单之后。这看起来很简单,但对我来说仍然是新的。我在将此应用于我的表格时遇到了一些问题。@King96,您能描述一下您在使用此方法时面临的问题吗?我不知道如何将您的问题与我的问题结合起来。当我尝试时,到处都会收到错误。不过现在正在阅读hashSet的更多内容。我很快会再试一次。尽管如此,还是要谢谢你。对于这种特殊情况,没有什么有用的东西。哇,这是一个非常详细的解释。非常感谢您抽出时间回答。我对你的答案投了赞成票,并将在第二天早上进一步测试后做出选择。再次感谢您的解释。若要转换为VB,请将private void
更改为private Sub
,移除开始大括号,将结束大括号更改为End Sub
,将var
更改为Dim
,将
更改为(字符串的)
,将=/code>更改为函数(),将':'
更改为':“c
,将[1]
更改为(1)
,并删除此处的分号
If Not foundList.Contains(word) Then
Private Sub Run()
' shortcut the file reads...
Dim items = ListBox1.Items.OfType(Of String)()
.SelectMany(Function(fn) File.ReadAllLines(fn))
.Select(Function(i) i.Split(":"c)(1))
Dim hash = New HashSet(Of String)(items)
ListBox2.Items.Clear()
ListBox2.Items.AddRange(hash.ToArray())
End Sub
Private Sub Run()
{
Dim items = ListBox1.Items.OfType(Of String)().
SelectMany(Function(fn) File.ReadAllLines(fn)).
Select(Function(i) i.Split(":"c)(1))
Dim hash = HashSet<string>(items)
ListBox2.Items.Clear()
Dim sorted = ListBox2.Sorted
ListBox2.Sorted = false
ListBox2.Items.AddRange(hash.ToArray())
ListBox2.Sorted = sorted
}
ListBox2.DataSource = (From line In IO.File.ReadLines(filePath)
Select line.Split(":"c)(1) Distinct).ToList