
No.5ベストアンサー
- 回答日時:
こんにちは。
もう一度、関数表から調べて作り直してみました。
>1000要素の配列が10万個くらいあるのです。
実際、元の質問のように、個別にデータを配列変数に入れる方法なら、ループで、変数に入れる時に数えればよいわけです。本当の問題は、配列にする前のデータです。これは、「最初に配列ありき」で始まっているから、難しいのだと思います。
そういう条件は、本来、配列構造を持ったものを、そのまま配列変数に代入するという方法が確立しているという条件が隠されているように思います。今、.Net FrameWork の ArrayList を試してみましたが、.Add で入れるなら、何もならないし、AddRange で入れるには、本来、そうした同じ、ArrayList の配列構造(というよりも、Collection)を持っていることが条件ですから、上手く行きませんでした。
これは、ワークシートのRange を前回の同じように、一列を切り出す方法です。
'Ar = Application.Index(Range("A1:A10000").Value, 0, 1)
以下のコードを見てください。VBA独特のコードです。
Excelのバージョンに依存するはすですが、Frequency 関数が使えます。ストレスなく、CountIf と同じように数を出すことができました。なお、今回は、WorksheetFunction から関数を取り出すことにしました。
Delta = Array(50, iMax) 51かと思いましたが、50と入れて、51以上になるようです。
'-------------------------------------------
Sub SampleTest2()
Dim Delta As Variant
Dim iMax As Long
Dim Ar As Variant
Dim Ret As Variant
Dim i As Long
Ar = Array(19, 9, 97, 100, 61, 59, 88, 29, 42, 39)
'Ar = Application.Index(Range("A1:A10000").Value, 0, 1)
iMax = WorksheetFunction.Max(Ar)
Delta = Array(50, iMax)
Ret = WorksheetFunction.Frequency(Ar, Delta)
i = Ret(2, 1)
MsgBox i
End Sub
No.4
- 回答日時:
これを質問した人なのですね。
>10億回くらい計算しないといけなくなるので
もしかして、データ数が、10億個あるのですか
多分、そもそも、配列のd(1000000000)の宣言が出来ないような
気がします。
No.3
- 回答日時:
こんにちは。
こういうのは、餅屋は餅屋なのですが、参りましたね。
今回のご質問に、前提が書かれていないようでしたが、本来の目的は、その計算処理スピードを上げたいということだったように思います。
それはなかなか難しいですね。ワークシート上で処理したほうが速い気がします。
なお、ワークシート関数は、仕様が明らかにはなっていませんが、配列を引数としてできるものとそうでないものがありますが、今回は、どうも上手くいきません。
とりあえず、数百万というデータ数に対するものとすると、今回の回答は、100点満点で、50点から60点の間です。一応、途中まで読んで、それで数を決めています。これでは、配列をワークシートに貼りつけて、ワークシート関数で計算したほうがはるかに上です。ただし、貼り付ける場合は、ループで張り付けずに、配列のまま貼りつけます。ADOに切り替えても、Excelの場合は、アーリーバインディングにしても、そのオブジェクトを生成する時の、オーバーヘッドが掛かってしまうので、期待した効果がありません。
'-------------------------------------------
Sub SampleTest1()
Dim Ar As Variant
Dim ret As Long
Ar = Array(19, 9, 97, 100, 61, 59, 88, 29, 42, 39)
ret = ArrayCountIf(Ar, 50)
MsgBox ret
End Sub
Function ArrayCountIf(BaseArray As Variant, arg As Long)
Dim ret As Long
Dim i As Long, j As Long
Dim Mn As Long
Dim Mx As Long
Mn = LBound(BaseArray)
Mx = UBound(BaseArray)
j = Mx - Mn + 1
With Application
For i = 1 To j
ret = .Small(BaseArray, i)
If ret > arg Then Exit For '以上
Next
End With
ArrayCountIf = j - i + 1
End Function
'-------------------------------------------
1000要素の配列が10万個くらいあるのです。
ワークシートに貼り付けたほうが早いのかもしれませんね。
どうもありがとうございます。
No.2
- 回答日時:
>エクセルVBAで配列aをワークシート関数countifで計算したいのですが、
>できないようです。代わりになるVBA関数はないでしょうか?
代わりになる関数は、解りませんが、自分で作っても
簡単だと思いますよ
>もしくは、代替可能な方法はないでしょうか?
配列をワークシートに展開して、
WorksheetFunction.CountIf
を使ったらいかがですか??
ワークシートに展開すればSumIfも同様です。
No.1
- 回答日時:
ワークシート関数を再利用せよ、という話で、シートを新たに作ってよければこう・・・
Sub Count1()
Dim newWorksheet As Excel.Worksheet
'やむを得ず暗黙の型変換。なんかCTypeの第二引数に指定出来ず。
'というか、CTypeのヘルプが出ないってことは、VBAにはないのかなぁ
Set newWorksheet = ActiveWorkbook.Worksheets.Add()
Dim a(5) As Integer
Dim i As Integer
a(0) = 7
a(1) = 4
a(2) = 1
a(3) = 5
a(4) = 3
a(5) = 6
For i = 0 To UBound(a)
newWorksheet.Cells(i + 1, 1).Value = a(i)
Next
MsgBox (Excel.WorksheetFunction.CountIf(newWorksheet.Range(newWorksheet.Cells(1, 1), newWorksheet.Cells(UBound(a) + 1, 1)), ">5"))
Application.DisplayAlerts = False
ActiveWorkbook.Worksheets(ActiveWorkBook.Worksheets.Count).Delete
Application.DisplayAlerts = True
End Sub
同様にこう。共通する部分は一緒にして省いても良し。
Sub Sum1()
Dim newWorksheet As Excel.Worksheet
'やむを得ず暗黙の型変換。なんかCTypeの第二引数に指定出来ず。
'というか、CTypeのヘルプが出ないってことは、VBAにはないのかなぁ
Set newWorksheet = ActiveWorkbook.Worksheets.Add()
Dim a(5) As Integer
Dim i As Integer
a(0) = 7
a(1) = 4
a(2) = 1
a(3) = 5
a(4) = 3
a(5) = 6
For i = 0 To UBound(a)
newWorksheet.Cells(i + 1, 1).Value = a(i)
Next
MsgBox (Excel.WorksheetFunction.SumIf(newWorksheet.Range(newWorksheet.Cells(1, 1), newWorksheet.Cells(UBound(a) + 1, 1)), ">5"))
Application.DisplayAlerts = False
ActiveWorkbook.Worksheets(ActiveWorkBook.Worksheets.Count).Delete
Application.DisplayAlerts = True
End Sub
======================
後はこれらを他のサブルーチンから呼び出せば良い
********************
そういうことをするな、という話であれば自分で作るしかない。
ここからの話は俺の作り方の都合上難度が上昇します。
自信がなくなったら引き返した方が無難。もっと簡単にも作れるんだが、VB.NETに憧れて汎用性を持たせてみたかった。本当はGenericsが欲しかった…。
********************
挿入->クラスモジュール
プロジェクトエクスプローラでこのモジュールを選択した状態で
プロパティウィンドウから
(オブジェクト名)をCollectionUtilに書き換える。
以後いくつかクラスモジュールを追加するので
'各クラスモジュールのオブジェクト名をClass XXXとか書いてあるXXXに書き換えて欲しい
'Class CollectionUtil
Option Explicit
Public Static Function ConvertFromArray(arr() As Integer) As Collection
Dim retval As New Collection
Dim i As Integer
For i = 0 To UBound(arr)
retval.Add (arr(i))
Next
Set ConvertFromArray = retval
End Function
Public Static Sub ConvertToArray(x As Collection, ByRef retval() As Integer)
Dim i As Integer
ReDim retval(x.Count - 1)
For i = 0 To x.Count - 1
retval(i) = x.Item(i + 1)
Next
End Sub
Public Static Function FindAll(c As Collection, f As IFilter) As Collection
Dim retval As Collection
Dim i As Integer
Set retval = New Collection
For i = 1 To c.Count
If f.isMatch(c.Item(i)) Then
retval.Add (c.Item(i))
End If
Next
Set FindAll = retval
End Function
Public Static Function Sum(c As Collection) As Integer
Dim retval As Integer
Dim i As Integer
For i = 1 To c.Count
retval = retval + CInt(c.Item(i))
Next
Sum = retval
End Function
===========
'Class IFilter
Option Explicit
Public Function isMatch(x As Integer) As Boolean
isMatch = True
End Function
=============
'Class MyLargerFilter
Option Explicit
Implements IFilter
Private threshold As Integer
Public Sub Class_initialize()
End Sub
Public Sub SetThreshold(x As Integer)
threshold = x
End Sub
Public Function IFilter_isMatch(x As Integer) As Boolean
If CInt(x) > threshold Then
IFilter_isMatch = True
Else
IFilter_isMatch = False
End If
End Function
==============
標準モジュールに戻って・・・例によって共通部分は単独で出来るように一応書いただけで省いても構わない
Sub Sum2()
Dim a(5) As Integer
Dim b() As Integer
Dim source As Collection
Dim destination As Collection
Dim Filter As MyLargerFilter
Dim CollectionUtil1 As New CollectionUtil
a(0) = 7
a(1) = 4
a(2) = 1
a(3) = 5
a(4) = 3
a(5) = 6
Set Filter = New MyLargerFilter
Filter.SetThreshold (5)
Set source = CollectionUtil1.ConvertFromArray(a)
Set destination = CollectionUtil1.FindAll(source, Filter)
MsgBox (CollectionUtil1.Sum(destination))
End Sub
Sub Count2()
Dim a(5) As Integer
Dim b() As Integer
Dim source As Collection
Dim destination As Collection
Dim Filter As MyLargerFilter
Dim CollectionUtil1 As New CollectionUtil
a(0) = 7
a(1) = 4
a(2) = 1
a(3) = 5
a(4) = 3
a(5) = 6
Set Filter = New MyLargerFilter
Filter.SetThreshold (5)
Set source = CollectionUtil1.ConvertFromArray(a)
Set destination = CollectionUtil1.FindAll(source, Filter)
CollectionUtil1.ConvertToArray destination, b
MsgBox (UBound(b) + 1)
End Sub
あとはその二つを
標準モジュールの
Sub Main()
Call Count2
Call Sum2
End Sub
ってところから呼び出してみる。
結果→2 13
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- その他(Microsoft Office) SUMIFとCOUNTIFの違いについて 4 2022/09/29 14:13
- Visual Basic(VBA) 重複したデータ(空白は除く)のVBA表記について 5 2022/08/15 12:41
- Excel(エクセル) 重複したデータ(空白は除く)のVBA表記について 4 2022/08/15 07:28
- Excel(エクセル) エクセル 関数について質問です。 2 2022/10/03 11:14
- Excel(エクセル) If関数に関する質問です。(再掲) 3 2022/10/01 20:51
- Excel(エクセル) エクセルの数式を等間隔にオートフィルできるやり方を教えていただきたいです。 実際の作業↓ A3セルに 7 2023/06/05 19:04
- Excel(エクセル) 【エクセル】COUNTIFの検索条件が可変する数字の場合の数式 1 2022/09/27 15:34
- Visual Basic(VBA) この関数と同じ処理をVBAで行うにはどうしたら良いでしょうか? これは、1列の中に同じ値が複数存在し 21 2022/07/07 07:48
- Excel(エクセル) Countifよりも早く重複数をカウントする方法ありますか? 18 2022/07/04 13:39
- Excel(エクセル) エクセルでフィルタ後の列の重複を回避したい 6 2022/10/13 12:50
このQ&Aを見た人はこんなQ&Aも見ています
-
worksheetFunctionクラスのVlookupプロパティを取得できません エラーへの対応
Visual Basic(VBA)
-
VBAのWorksheetFunctionの引数に配列を使いたい
PowerPoint(パワーポイント)
-
excel VBA 2つのシートの特定の列を比較して同じ値のセルがあったらその行を上書きしたい
Excel(エクセル)
-
-
4
エクセルのラベルの値(文字列)を垂直方向で中央揃えにするには?
Excel(エクセル)
-
5
メッセージボックスを前面に表示させるには?
Visual Basic(VBA)
-
6
VBA コレクションに2次元配列を追加して取り出す方法
Visual Basic(VBA)
-
7
VBAでブックを非表示で開いて処理して閉じる方法
Excel(エクセル)
-
8
VBAで配列の計算
Excel(エクセル)
-
9
Application.Matchで特定行の検索
Visual Basic(VBA)
-
10
VBA public変数はどのようなことをしたら解放されますか?
Visual Basic(VBA)
-
11
Countifよりも早く重複数をカウントする方法ありますか?
Excel(エクセル)
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
VBA 変数名に変数を使用したい。
-
vba フィルター 複数条件 3つ以...
-
Excel2010のinputboxで複数デー...
-
ジャグ配列生成時の1オリジン
-
配列のペースト出力結果の書式...
-
1次元配列をワークシートに高...
-
excel vbaの配列なんですが・・・
-
配列の中から最大値だけ取り出...
-
C#でbyte配列から画像を表示さ...
-
VBA 桁数が混在するソート
-
VB.NETにて、構造体へデータを...
-
free()関数の多用 と Segment...
-
countif/sumifのようなVBA関数
-
エクセルでXY座標に並べられた...
-
COBOLの基本的な事なので...
-
C言語 ポインタと配列
-
エクセル(VBA)の空白配列の削除...
-
Redim とEraseの違いは?
-
大量の変数を定義するにはどう...
-
2次元配列を部分的に削除する方法
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
VBA 変数名に変数を使用したい。
-
vba フィルター 複数条件 3つ以...
-
C#でbyte配列から画像を表示さ...
-
配列の中の最大値とそのインデ...
-
エクセルでXY座標に並べられた...
-
Dir関数で読み取り順を操作でき...
-
配列のペースト出力結果の書式...
-
COBOLの基本的な事なので...
-
複数のtextboxの処理を一括で行...
-
構造体配列の特定のメンバーをF...
-
大量の変数を定義するにはどう...
-
CheckBoxの配列化
-
Excelのメモリ(配列)の上限は2G...
-
VB6のメモリ解放に関して
-
ReDim PreserveよりもReDimが遅い
-
Excel2010のinputboxで複数デー...
-
定数配列の書き方
-
コンボボックスのインデックス...
-
EXCELを使って、アクセスログを...
-
レコードセットの中身を配列に...
おすすめ情報