« VB ArrayList,LIST(Of T),配列 比較 | トップページ | VB MySQLのデータをCSVファイルに出力するツール »

2015年3月19日 (木)

VB たかがソート,されどSort

No,Dataの2つの配列を連動してDataをキーに降順でソートしたい
のですが,あれこれはまっていました。

下記のようにソートしたい。
ソート前
No Data
1 0.154
2 0.683
3 0.995
4 0.482

ソート後
No Data
3 0.995
2 0.683
4 0.482
1 0.154

VisualBasic6.0やVBAではこういった場合のソート用関数が無いので地味にループして比較でソートするオーソドックスな方法となります。
しかし最新の.NETの時代,ネット検索した感じでは,ソート1つ取ってもなにやら様々な方法があるらしい。主にコレクションのクラスを使ってソートするようですが私の前回のブログ記事(VB ArrayList,LIST(Of T),配列 比較)で掲載した通り私自身コレクションが今1つ分かっていなくてソートとなるとさらに分からない。
でも,出来ることならカッコ良く,しかも高速にソートしたい。
と言うことで無い頭で考えるのは止めて,ひたすらネット検索した結果,いくつかのソート方法を試すことが出来ました。

結果
※シリアルNoと乱数(小数点型)のデータ1万行をソートした時間

項目 時間[s]  コメント
①単純なループでのソート 0.680 
②ArrayListを介しArray.Sort 0.042   
③SortedListでソート その1 0.055 
④SortedListでソート その2 0.076      降順を別ソート
⑤Dictionaryでソート 0.209   昇順のみのソート
⑥単純なArray.Sort 0.005   降順を別ソート

丸付き数字はネット検索で見つけた順番ですが,その順番で試していきました。
オーソドックスな方法が一番軽いイメージを持っているため①の単純ソートが一番遅いのが意外でした。
⑤のDictionaryでのソートは降順にソートする方法が分からず昇順のみの結果です。そのため若干時間が足されます。
実は⑤までやって終わる予定だったのですが最後のひと押しと言うことでさらに検索したところ⑥の単純なArray.Sortを見つけ,これが非常に高速で当たりでした。

結論
単純なArray.Sortでソートする。

もちろん,それぞれの方法にメリット,デメリットがあります。例えばSortedListはどんどんデータを足していくことが出来る上,その都度ソートされますので,その意味では代替の方法がありません(出来たとしても多分遅くなる)。また,要素が文字列だったりすると結果が変わってくるかも知れません。
それから,OrderByなど理解不足でまだ試していない方法がいくつかあります。


それにしても,この情報の海のなかでピンポイントで望む情報を得るのは難しいですね。何事も最後のひと押し,粘りが大切なことを実感しました。


検証に使用したVisualBasicのソースコード
-----------------------------------------------------------
Public Class Form1

'昇順ソート用
Shared Function CreateReversed(Of TKey, TValue)(ByVal source As SortedList(Of TKey, TValue)) As SortedList(Of TKey, TValue)
Return New SortedList(Of TKey, TValue)(source, New ReverseComparer(Of TKey)(source.Comparer))
End Function

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

Dim sw As New System.Diagnostics.Stopwatch()
Dim loop1 As Integer
Dim loop2 As Integer

'元データを準備,シリアルNoと乱数のデータ1万行
Dim no(10000) As Integer
Dim data(10000) As Double
Dim r As New System.Random(1000)
For loop1 = 0 To 10000
no(loop1) = loop1
data(loop1) = r.NextDouble()
Next loop1

'①単純なループでのソート,降順
sw.Start()
Dim swapData As Double
Dim swapNo As Integer
Dim no1(10000) As Integer
Dim data1(10000) As Double
For loop1 = 0 To 10000
no1(loop1) = no(loop1)
data1(loop1) = data(loop1)
Next loop1
For loop1 = 0 To 10000
For loop2 = 10000 To loop1 Step -1
If data1(loop1) < data1(loop2) Then
swapNo = no1(loop1)
no1(loop1) = no1(loop2)
no1(loop2) = swapNo
swapData = data1(loop1)
data1(loop1) = data1(loop2)
data1(loop2) = swapData
End If
Next loop2
Next loop1
sw.Stop()
Console.WriteLine(sw.Elapsed)
sw.Reset()


'②ArrayListを介しArray.Sortでソート,降順
sw.Start()
Dim Mycompare = New myReverser
Dim no2 As ArrayList = New ArrayList
Dim data2 As ArrayList = New ArrayList
For loop1 = 0 To 10000
no2.Add(no(loop1))
data2.Add(data(loop1))
Next loop1
Dim ar(1)() As Object
ar(0) = no2.ToArray
ar(1) = data2.ToArray
Array.Sort(ar(1), ar(0), Mycompare)
Array.Sort(ar(1), ar(1), Mycompare)
sw.Stop()
Console.WriteLine(sw.Elapsed)
sw.Reset()


'③SortedListでソート その1,降順
sw.Start()
Dim data3 = New SortedList(New myReverserClass())
For loop1 = 0 To 10000
data3.Add(data(loop1), no(loop1))
Next loop1
sw.Stop()
Console.WriteLine(sw.Elapsed)
sw.Reset()


'④SortedListでソート その2,降順
sw.Start()
Dim data4A As New SortedList(Of Double, Integer)()
For loop1 = 0 To 10000
data4A.Add(data(loop1), no(loop1))
Next loop1
Dim data4B As New List(Of KeyValuePair(Of Double, Integer))(CreateReversed(data4A))
sw.Stop()
Console.WriteLine(sw.Elapsed)
sw.Reset()


'⑤Dictionaryでソート,昇順(降順の方法分からず)
sw.Start()
Dim data5A As New Dictionary(Of Double, Integer)()
For loop1 = 0 To 10000
data5A.Add(data(loop1), no(loop1))
Next loop1
Dim data5B As New List(Of KeyValuePair(Of Double, Integer))(data5A)
data5B.Sort(Function(x, y) String.Compare(x.Key, y.Key))
sw.Stop()
Console.WriteLine(sw.Elapsed)
sw.Reset()


'⑥単純なArray.Sort,降順
sw.Start()
Dim no6(10000) As Integer
Dim data6(10000) As Double
For loop1 = 0 To 10000
no6(loop1) = no(loop1)
data6(loop1) = data(loop1)
Next loop1
Array.Sort(data6, no6)
Array.Reverse(no6)
Array.Reverse(data6)
sw.Stop()
Console.WriteLine(sw.Elapsed)
sw.Reset()

Application.Exit()

End Sub

End Class

'昇順ソート用
Class ReverseComparer(Of T)
Implements IComparer(Of T)
Private comparer As IComparer(Of T)
Public Sub New(ByVal comparer As IComparer(Of T))
Me.comparer = comparer
End Sub
Public Function Compare(ByVal x As T, ByVal y As T) As Integer Implements IComparer(Of T).Compare
Return comparer.Compare(y, x)
End Function
End Class

'昇順ソート用
Public Class myReverser
Implements IComparer
Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements System.Collections.IComparer.Compare
Return New CaseInsensitiveComparer().Compare(y, x)
End Function
End Class

'昇順ソート用
Public Class myReverserClass : Implements IComparer
Private Function Compare(ByVal x As Object, ByVal y As Object) _
As Integer Implements IComparer.Compare
Return ((New CaseInsensitiveComparer()).Compare(y, x))
End Function
End Class

|

« VB ArrayList,LIST(Of T),配列 比較 | トップページ | VB MySQLのデータをCSVファイルに出力するツール »

コメント

コメントを書く



(ウェブ上には掲載しません)




トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/206107/61303843

この記事へのトラックバック一覧です: VB たかがソート,されどSort:

« VB ArrayList,LIST(Of T),配列 比較 | トップページ | VB MySQLのデータをCSVファイルに出力するツール »