<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>配列 | VBA・GAS・Pythonで仕事を楽しく効率化</title>
	<atom:link href="https://officevba.info/category/vba%E5%85%B1%E9%80%9A/%E9%85%8D%E5%88%97/feed/" rel="self" type="application/rss+xml" />
	<link>https://officevba.info</link>
	<description>仕事の役に立つVBA・GAS・Pythonのコードを紹介していきます。</description>
	<lastBuildDate>Sun, 22 Aug 2021 10:44:01 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.7.1</generator>

<image>
	<url>https://officevba.info/wp-content/uploads/2017/04/cropped-Excel_1-32x32.jpg</url>
	<title>配列 | VBA・GAS・Pythonで仕事を楽しく効率化</title>
	<link>https://officevba.info</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>連想配列（Dictionary）④-複数項目を一気に連想配列に格納して取得する方法-</title>
		<link>https://officevba.info/multidictionary/</link>
					<comments>https://officevba.info/multidictionary/#respond</comments>
		
		<dc:creator><![CDATA[okumasahito]]></dc:creator>
		<pubDate>Sun, 22 Aug 2021 10:44:01 +0000</pubDate>
				<category><![CDATA[連想配列]]></category>
		<category><![CDATA[配列]]></category>
		<category><![CDATA[Dictionary]]></category>
		<category><![CDATA[複数]]></category>
		<guid isPermaLink="false">https://officevba.info/?p=2285</guid>

					<description><![CDATA[目次 連想配列（Dictionary）で一つのキーに対して複数のアイテムを格納する方法を検討連想配列（Dictionary）で一つのキーに対して複数のアイテムを格納するには配列を使う連想配列を用いて集計をするためのサンプ [&#8230;]]]></description>
										<content:encoded><![CDATA[
  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-2" checked><label class="toc-title" for="toc-checkbox-2">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">連想配列（Dictionary）で一つのキーに対して複数のアイテムを格納する方法を検討</a></li><li><a href="#toc2" tabindex="0">連想配列（Dictionary）で一つのキーに対して複数のアイテムを格納するには配列を使う</a></li><li><a href="#toc3" tabindex="0">連想配列を用いて集計をするためのサンプルシート</a></li><li><a href="#toc4" tabindex="0">①一つのキーに対してアイテムにセル範囲を格納した配列を割り当てる</a></li><li><a href="#toc5" tabindex="0">②Dictionary型のオブジェクトを配列として宣言する</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">連想配列（Dictionary）で一つのキーに対して複数のアイテムを格納する方法を検討</span></h2>
<p>事務仕事を行っているとVBAのほかExcelの関数も使用する機会が多いです。</p>
<p>中でもVlookup関数やSUMIFS関数の頻度が高いのですが、これらの関数は対象の行数が多いと結果の表示に時間がかかることがあります。<br />
（Office2016からVlookup関数は高速化されましたが、VBAの中で組み込むと計算が終了する前に次の処理に移ってしまったり、速度が遅かったりします。）</p>
<p>以前から連想配列（Dictionary）を用いてこれらの関数と同様の処理を高速にする方法をご紹介していますが、Dictionary型はキーとアイテムが一対一の関係にあるので、複数のアイテムを参照したい場合、都度Dicrionaryを宣言するのが手間になります。</p>
<p>今回はこの問題を解消した、複数カラム（アイテム）を参照する方法をご紹介します。</p>
<h2><span id="toc2">連想配列（Dictionary）で一つのキーに対して複数のアイテムを格納するには配列を使う</span></h2>
<p>手順の考え方を先にお伝えすると、配列を使用することで一つのキーに対して複数のアイテムを持つことができるようになります。<br />
配列の使い方は以下2通りが想定されました。</p>
<p>①一つのDictionary型のオブジェクトを宣言して、一つのキーに対してアイテムにセル範囲を格納した配列を割り当てる</p>
<p>②Dictionary型のオブジェクトを配列として宣言して、一つのキーに対して一つのアイテムを格納する。</p>
<p>少しイメージがつきにくいと思いますので、サンプルシートを用いて具体的な手順を記載します。</p>
<h2><span id="toc3">連想配列を用いて集計をするためのサンプルシート</span></h2>
<p><a href="https://officevba.info/wp-content/uploads/2021/08/b539b93fede403dd99bca9a8e394438a.jpg"><img fetchpriority="high" decoding="async" src="https://officevba.info/wp-content/uploads/2021/08/b539b93fede403dd99bca9a8e394438a-700x394.jpg" alt="VBA158" width="700" height="394" /></a></p>
<p>ある会社における店舗ごとの3か月ごとの売り上げ実績表のイメージになります。</p>
<p>A列に店固有のコード・B列は店舗名称になります。<br />
C列には商品コードが入っていて、D列から後は3か月分の数量と原価・売価が書いてある表です。</p>
<p>サンプルで用意したこちらのシートは店舗数が77店舗、行数は約40,000行となっています。<br />
Excelで加工するワークシートとしては容量が大きめかと思います。</p>
<p>こちらの数量・原価・売価について<span class="marker-under">連想配列を用いて店舗ごとに集計するというのが今回ご紹介するコードの目的</span>になります。</p>
<p>また、同じ処理はSUMIFS関数やピポットテーブルを使えば行うことができます。<br />
ただし、SUMIFS関数は処理が遅い、ピポットテーブルはVBAで実行すると独特の挙動になるため、準備と後処理が面倒くさいのがネックになります。</p>
<p>その点連想配列を用いればスマートかつ高速に処理が可能です。</p>
<h2><span id="toc4">①一つのキーに対してアイテムにセル範囲を格納した配列を割り当てる</span></h2>
<div class="VBACode">Sub 店舗ごと金額集計Itemを直接配列に格納()<br />
<br />
<span class="VBA_Tab1"><span class="VBA_Comment">’エラー起こるので非推奨</span></span><br />
<span class="VBA_Tab1">Sheets(1).Select</span><br />
<span class="VBA_Tab1">Dim JANシート</span><br />
<span class="VBA_Tab1">Set JANシート = Sheets(1)</span><br />
<br />
<span class="VBA_Tab1">Dim JANシート下端行</span><br />
<span class="VBA_Tab1">JANシート下端行 = JANシート.Cells(Rows.Count, 1).End(xlUp).Row</span><br />
<br />
<span class="VBA_Tab1">Dim JANシート範囲</span><br />
<span class="VBA_Tab1">JANシート範囲 = Range(JANシート.Cells(1, 1), JANシート.Cells(JANシート下端行, 15))</span><br />
<br />
<span class="VBA_Tab1">Dim i, x, k</span><br />
<span class="VBA_Tab1">Dim dict実績 As Object</span><br />
<br />
<span class="VBA_Tab1">Set dict実績 = CreateObject(&#8220;Scripting.Dictionary&#8221;)</span><br />
<br />
<span class="VBA_Tab1">Dim itemRange</span><br />
<span class="VBA_Tab1">Dim storeCode()</span><br />
<span class="VBA_Tab1">x = 0</span><br />
<br />
<span class="VBA_Tab1">For i = 3 To JANシート下端行</span><br />
<span class="VBA_Tab2">If dict実績.Exists(JANシート範囲(i, 1)) = False Then</span><br />
<span class="VBA_Tab3">dict実績.Add (JANシート範囲(i, 1)), Range(Cells(i, 1), Cells(i, 15))</span><br />
<br />
<span class="VBA_Tab3">ReDim Preserve storeCode(x)</span><br />
<span class="VBA_Tab3">storeCode(x) = JANシート範囲(i, 1)</span><br />
<span class="VBA_Tab3">x = x + 1</span><br />
<br />
<span class="VBA_Tab2">Else</span><br />
<span class="VBA_Tab3">For k = 4 To 15</span><br />
<span class="VBA_Tab4">dict実績(JANシート範囲(i, 1))(k) = dict実績(JANシート範囲(i, 1))(k) + JANシート範囲(i, k)</span><br />
<span class="VBA_Tab3">Next k</span><br />
<span class="VBA_Tab2">End If</span><br />
<span class="VBA_Tab1">Next i</span><br />
<br />
<span class="VBA_Tab1">Sheets.Add before:=Sheets(1)</span><br />
<span class="VBA_Tab1">Dim r</span><br />
<span class="VBA_Tab1">r = Range(Sheets(1).Cells(1, 1), Sheets(1).Cells(UBound(storeCode) + 2, 15))</span><br />
<span class="VBA_Tab1">For i = 1 To UBound(storeCode) + 1</span><br />
<span class="VBA_Tab2">r(i + 1, 1) = storeCode(i － 1)  <span class="VBA_Comment">’行番号は2からスタート、配列は0からスタート</span></span><br />
<span class="VBA_Tab2">For k = 4 To 15</span><br />
<span class="VBA_Tab3">r(i + 1, k) = dict実績(r(i + 1, 1))(k)</span><br />
<span class="VBA_Tab2">Next k</span><br />
<span class="VBA_Tab1">Next i</span><br />
<span class="VBA_Tab1">Range(Sheets(1).Cells(1, 1), Sheets(1).Cells(UBound(storeCode) + 1, 15)) = r</span><br />
<br />
<span class="VBA_Tab1">Set dict実績 = Nothing</span><br />
<span class="VBA_Tab1">Set JANシート = Nothing</span><br />
<br />
End Sub</div>
<p>dict実績という連動配列を宣言し、店舗コードをキーに、その行に含まれている実績を配列に格納します。<br />
重複されるデータは繰り返し処理を用いてアイテムの配列に値を追加していく流れになります。</p>
<p>こちらで処理を実行すると、なぜかよくわからないのですが、<span class="marker-under">セルの値が更新される不具合（？）が生じました。</span><br />
実績自体は別シートに出力するので、もともとのシートは別に保存しておけば大丈夫かとも思いますが少し不気味な結果です。</p>
<p>セルを配列に格納する場合はセルの値を格納するというよりは、セルオブジェクトを配列に格納していると思われます。<br />
そのため、加算をしたものがダイレクトにセルの値に反映されたと推測されるのですが、通常セルを配列に格納してもこの事象は起こらない気がしますので、正しいかどうかは不明です。</p>
<p>どのような原因にせよ連想配列のアイテムにセルを格納した配列を用いるのはあまり良くなさそうです。</p>
<p>一応、セルの値を配列に格納して更新する方法も試したのですが、<span class="marker-under">こちらはセルの値が加算されず、最初に格納されたアイテムだけが吐き出される</span>結果になりました。</p>
<p>こちらも不具合かもしれませんが、私には判断がつきませんでした。連想配列の挙動は少し不思議な感じがします。<br />
それにそもそも最初にArray関数を使うところの記述が面倒で、要素数が増えるとかなり辛いのでそもそも却下です。</p>
<div class="VBACode">Sub 店舗ごと金額集計ItemにArray関数で配列を格納()<br />
<br />
<span class="VBA_Tab1"><span class="VBA_Comment">’エラー起こるし、きちんと動かない</span></span><br />
<span class="VBA_Tab1">Sheets(1).Select</span><br />
<span class="VBA_Tab1">Dim JANシート</span><br />
<span class="VBA_Tab1">Set JANシート = Sheets(1)</span><br />
<br />
<span class="VBA_Tab1">Dim JANシート下端行</span><br />
<span class="VBA_Tab1">JANシート下端行 = JANシート.Cells(Rows.Count, 1).End(xlUp).Row</span><br />
<br />
<span class="VBA_Tab1">Dim JANシート範囲</span><br />
<span class="VBA_Tab1">JANシート範囲 = Range(JANシート.Cells(1, 1), JANシート.Cells(JANシート下端行, 15))</span><br />
<br />
<span class="VBA_Tab1">Dim i, x, k</span><br />
<span class="VBA_Tab1">Dim dict実績 As Object</span><br />
<br />
<span class="VBA_Tab1">Set dict実績 = CreateObject(&#8220;Scripting.Dictionary&#8221;)</span><br />
<br />
<span class="VBA_Tab1">Dim itemRange</span><br />
<span class="VBA_Tab1">Dim storeCode()</span><br />
<span class="VBA_Tab1">x = 0</span><br />
<br />
<span class="VBA_Tab1">For i = 3 To JANシート下端行</span><br />
<span class="VBA_Tab2">If dict実績.Exists(JANシート範囲(i, 1)) = False Then</span><br />
<span class="VBA_Tab3">dict実績.Add (JANシート範囲(i, 1)), Array(Cells(i, 1).Value, Cells(i, 2).Value, Cells(i, 3).Value, Cells(i, 4).Value, Cells(i, 5).Value, Cells(i, 6).Value, Cells(i, 7).Value, Cells(i, 8).Value, Cells(i, 9).Value, Cells(i, 10).Value, Cells(i, 11).Value, Cells(i, 12).Value, Cells(i, 13).Value, Cells(i, 14).Value, Cells(i, 15))</span><br />
<br />
<span class="VBA_Tab3">ReDim Preserve storeCode(x)</span><br />
<span class="VBA_Tab3">storeCode(x) = JANシート範囲(i, 1)</span><br />
<span class="VBA_Tab3">x = x + 1</span><br />
<br />
<span class="VBA_Tab2">Else</span><br />
<span class="VBA_Tab3">For k = 4 To 15</span><br />
<span class="VBA_Tab4">dict実績(JANシート範囲(i, 1))(k － 1) = dict実績(JANシート範囲(i, 1))(k － 1) + Cells(i, k).Value</span><br />
<span class="VBA_Tab3">Next k</span><br />
<span class="VBA_Tab2">End If</span><br />
<span class="VBA_Tab1">Next i</span><br />
<br />
<span class="VBA_Tab1">Sheets.Add before:=Sheets(1)</span><br />
<span class="VBA_Tab1">Dim r</span><br />
<span class="VBA_Tab1">r = Range(Sheets(1).Cells(1, 1), Sheets(1).Cells(UBound(storeCode) + 2, 15))</span><br />
<br />
<span class="VBA_Tab1">For i = 0 To UBound(storeCode)</span><br />
<span class="VBA_Tab2">r(i + 2, 1) = storeCode(i)  <span class="VBA_Comment">’行番号は2からスタート、配列は0からスタート</span></span><br />
<span class="VBA_Tab2">For k = 4 To 15</span><br />
<span class="VBA_Tab3">r(i + 2, k) = dict実績(r(i + 2, 1))(k － 1)</span><br />
<span class="VBA_Tab2">Next k</span><br />
<span class="VBA_Tab1">Next i</span><br />
<span class="VBA_Tab1">Range(Sheets(1).Cells(1, 1), Sheets(1).Cells(UBound(storeCode) + 2, 15)) = r</span><br />
<br />
<span class="VBA_Tab1">Set dict実績 = Nothing</span><br />
<span class="VBA_Tab1">Set JANシート = Nothing</span><br />
<br />
End Sub</div>
<h2><span id="toc5">②Dictionary型のオブジェクトを配列として宣言する</span></h2>
<p>上記の2つの配列を使う方法がうまくいかなかったので、他に方法を検討して思いついたのがこちらの方法です。<br />
若干手順が面倒ですが、繰り返し処理を付け加えるだけで上記①と似た手間になるので私としては現在この方法が最も現実的かと思います。</p>
<div class="VBACode">Sub 店舗ごと金額集計連想配列を配列として宣言()<br />
<br />
<span class="VBA_Tab1"><span class="VBA_Comment">’宣言のところで繰り返しが必要だが基本使いやすい</span></span><br />
<br />
<span class="VBA_Tab1">Sheets(1).Select</span><br />
<span class="VBA_Tab1">Dim JANシート</span><br />
<span class="VBA_Tab1">Set JANシート = Sheets(1)</span><br />
<br />
<span class="VBA_Tab1">Dim JANシート下端行</span><br />
<span class="VBA_Tab1">JANシート下端行 = JANシート.Cells(Rows.Count, 1).End(xlUp).Row</span><br />
<br />
<span class="VBA_Tab1">Dim JANシート範囲</span><br />
<span class="VBA_Tab1">JANシート範囲 = Range(JANシート.Cells(1, 1), JANシート.Cells(JANシート下端行, 15))</span><br />
<br />
<span class="VBA_Tab1">Dim i, x, k</span><br />
<span class="VBA_Tab1">Dim dict実績(1 To 15) As Object</span><br />
<br />
<span class="VBA_Tab1">For k = 1 To 15</span><br />
<span class="VBA_Tab2">Set dict実績(k) = CreateObject(&#8220;Scripting.Dictionary&#8221;)</span><br />
<span class="VBA_Tab1">Next k</span><br />
<br />
<span class="VBA_Tab1">Dim itemRange</span><br />
<span class="VBA_Tab1">Dim storeCode()</span><br />
<span class="VBA_Tab1">x = 0</span><br />
<br />
<span class="VBA_Tab1"><span class="VBA_Comment">’Itemにセルを格納した配列はあまり良くない?</span></span><br />
<span class="VBA_Tab1"><span class="VBA_Comment">’array使ってvalueを格納すると加算ができない</span></span><br />
<span class="VBA_Tab1"><span class="VBA_Comment">’variant型の変数にセルを直接配列として格納するとセルの値が変更される</span></span><br />
<br />
<span class="VBA_Tab1">For i = 3 To JANシート下端行</span><br />
<span class="VBA_Tab2">If dict実績(1).Exists(JANシート範囲(i, 1)) = False Then</span><br />
<span class="VBA_Tab3">For k = 1 To 15</span><br />
<span class="VBA_Tab4">dict実績(k).Add (JANシート範囲(i, 1)), JANシート範囲(i, k)</span><br />
<span class="VBA_Tab3">Next k</span><br />
<br />
<span class="VBA_Tab3">ReDim Preserve storeCode(x)</span><br />
<span class="VBA_Tab3">storeCode(x) = JANシート範囲(i, 1)</span><br />
<span class="VBA_Tab3">x = x + 1</span><br />
<span class="VBA_Tab2">Else</span><br />
<span class="VBA_Tab3">For k = 4 To 15</span><br />
<span class="VBA_Tab4">dict実績(k)(JANシート範囲(i, 1)) = dict実績(k)(JANシート範囲(i, 1)) + JANシート範囲(i, k)</span><br />
<span class="VBA_Tab3">Next k</span><br />
<span class="VBA_Tab2">End If</span><br />
<span class="VBA_Tab1">Next i</span><br />
<br />
<span class="VBA_Tab1">Sheets.Add before:=Sheets(1)</span><br />
<span class="VBA_Tab1">Dim r</span><br />
<span class="VBA_Tab1">r = Range(Sheets(1).Cells(1, 1), Sheets(1).Cells(UBound(storeCode) + 2, 15))</span><br />
<span class="VBA_Tab1">For i = 0 To UBound(storeCode)</span><br />
<span class="VBA_Tab2">r(i + 2, 1) = storeCode(i)  <span class="VBA_Comment">’行番号は2からスタート、配列は0からスタート</span></span><br />
<span class="VBA_Tab2">For k = 4 To 15</span><br />
<span class="VBA_Tab3">r(i + 2, k) = dict実績(k)(r(i + 2, 1))</span><br />
<span class="VBA_Tab2">Next k</span><br />
<span class="VBA_Tab1">Next i</span><br />
<span class="VBA_Tab1">Range(Sheets(1).Cells(1, 1), Sheets(1).Cells(UBound(storeCode) + 2, 15)) = r</span><br />
<br />
<span class="VBA_Tab1">For k = 1 To 15</span><br />
<span class="VBA_Tab2">Set dict実績(k) = Nothing</span><br />
<span class="VBA_Tab1">Next k</span><br />
<span class="VBA_Tab1">Set JANシート = Nothing</span><br />
<br />
End Sub</div>
<p>先ほどとは違いDictionary型を配列として宣言し、<span class="marker-under">15個分の連想配列を繰り返し処理で準備</span>します。</p>
<p>吐き出すときはdict実績(インデックス番号)(“キー”)で出力できるようにして、かつ列番号とインデックス番号を揃えておくことで見やすくもなります。<br />
こちらの処理は問題なく動きました。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://officevba.info/multidictionary/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>連想配列（Dictionary）③-キー一覧を取得する方法と高速化のテクニック-</title>
		<link>https://officevba.info/dictionary-keys/</link>
					<comments>https://officevba.info/dictionary-keys/#respond</comments>
		
		<dc:creator><![CDATA[okumasahito]]></dc:creator>
		<pubDate>Sun, 22 Aug 2021 10:10:22 +0000</pubDate>
				<category><![CDATA[連想配列]]></category>
		<category><![CDATA[配列]]></category>
		<category><![CDATA[Dictionary]]></category>
		<category><![CDATA[Keys]]></category>
		<category><![CDATA[sumifs]]></category>
		<guid isPermaLink="false">https://officevba.info/?p=2274</guid>

					<description><![CDATA[目次 キー一覧を入力するのが面倒？サンプルシート連想配列のキー一覧を出力する方法①-Keysプロパティを使用-連想配列のキー一覧を出力する方法②-通常の配列を使用する連想配列を使用する際の最速の処理方法について キー一覧 [&#8230;]]]></description>
										<content:encoded><![CDATA[
  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-4" checked><label class="toc-title" for="toc-checkbox-4">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">キー一覧を入力するのが面倒？</a></li><li><a href="#toc2" tabindex="0">サンプルシート</a></li><li><a href="#toc3" tabindex="0">連想配列のキー一覧を出力する方法①-Keysプロパティを使用-</a></li><li><a href="#toc4" tabindex="0">連想配列のキー一覧を出力する方法②-通常の配列を使用する</a></li><li><a href="#toc5" tabindex="0">連想配列を使用する際の最速の処理方法について</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">キー一覧を入力するのが面倒？</span></h2>
<p>連想配列（Dictionary）を使用するようになって行数の多いデータの加工が楽になったのですが、連想配列を使用する際によく使う「キーの一覧を別シートに出力する方法」がないか調べてみたのでその手順についてご紹介します。</p>
<p>連想配列のキー一覧を出力するケースとしては、SUMIFS関数の代わりに連想配列を使用した場合などがあります。<br />
キー一覧を別シートに出力して、その右に連想配列に格納されている集計結果を表示させることが多いと思います。</p>
<p>これを知らないとせっかく連想配列を用いていても、別シートを作成する際に元シートのキー部分をコピーして貼り付け後に重複削除をするという面倒な手順を踏むことになります。</p>
<h2><span id="toc2">サンプルシート</span></h2>
<p>サンプルシートは前回こちらの記事で使ったものと同じものになります。<br />
商品の売り上げ一覧表の中で商品ごとの金額の合計を別シートに出力する用途をイメージしたものです。</p>
<p><a href="https://officevba.info/dictionary-sumifs/" target="_blank">前回ご紹介したコード</a>では、すでに重複のないJANコードの一覧はすでに別シートに出力している状態でVBAを実行していましたが、今回はその重複のないJANコード一覧も出力するフローを想定しています。</p>
<p><a href="https://officevba.info/wp-content/uploads/2021/07/439815dd8e5784bbb079387253538967.jpg"><img decoding="async" src="https://officevba.info/wp-content/uploads/2021/07/439815dd8e5784bbb079387253538967-700x814.jpg" alt="vba156シート1" width="700" height="814" /></a></p>
<h2><span id="toc3">連想配列のキー一覧を出力する方法①-Keysプロパティを使用-</span></h2>
<p>まずオーソドックスな方法です。<br />
連想配列に格納後、Keyプロパティでキーの一覧を取得します。</p>
<p>前回ご紹介したコードとほぼ同じですが、連想配列の宣言の時に参照設定を使用する方法にしないとKeyプロパティは参照できないようです。</p>
<div class="VBACode">Sub DictionaryでKeyを使ってキーの一覧取得()<br />
<br />
<span class="VBA_Tab1"><span class="VBA_Comment0">’開始時間の記載</span></span><br />
<span class="VBA_Tab1">Debug.Print &#8220;Dictionaryで項目入力開始-&#8221; &#038; Time</span><br />
<br />
<span class="VBA_Tab1"><span class="VBA_Comment0">’Dim dicJAN</span></span><br />
<span class="VBA_Tab1"><span class="VBA_Comment0">’Set dicJAN = CreateObject(&#8220;Scripting.Dictionary&#8221;)</span></span><br />
<span class="VBA_Tab1"><span class="marker-under">Dim dicJAN As New Scripting.Dictionary</span></span><br />
<br />
<span class="VBA_Tab1"><span class="VBA_Comment0">’JAN と金額の合計をDictionaryに格納</span></span><br />
<span class="VBA_Tab1">Dim y, i</span><br />
<span class="VBA_Tab1">With Sheets(1)</span><br />
<span class="VBA_Tab2">y = .Cells(Rows.Count, 1).End(xlUp).Row</span><br />
<span class="VBA_Tab2">For i = 2 To y</span><br />
<span class="VBA_Tab3"><span class="VBA_Comment0">’JANコードの登録がない場合、Dictionaryに追加</span></span><br />
<span class="VBA_Tab3">If Not dicJAN.Exists(.Cells(i, 1).Value) Then</span><br />
<span class="VBA_Tab4">dicJAN.Add .Cells(i, 1).Value, .Cells(i, 5)</span><br />
<span class="VBA_Tab3"><span class="VBA_Comment0">’JANコードの登録がある場合、Dictionaryに格納されている値を更新</span></span><br />
<span class="VBA_Tab3">Else</span><br />
<span class="VBA_Tab4">dicJAN(.Cells(i, 1).Value) = dicJAN(.Cells(i, 1).Value) + .Cells(i, 5)</span><br />
<span class="VBA_Tab3">End If</span><br />
<span class="VBA_Tab2">Next i</span><br />
<span class="VBA_Tab1">End With</span><br />
<br />
<span class="VBA_Tab1"><span class="VBA_Comment0">’JAN一覧B列に合計金額の出力</span></span><br />
<span class="VBA_Tab1">Dim r</span><br />
<span class="VBA_Tab1">r = Range(Sheets(2).Cells(1, 1), Sheets(2).Cells(dicJAN.Count + 1, 2))</span><br />
<br />
<span class="VBA_Tab2">For i = 0 To dicJAN.Count － 1</span><br />
<span class="VBA_Tab3">r(i + 2, 1) = <span class="marker-under">dicJAN.Keys(i)</span></span><br />
<span class="VBA_Tab3">r(i + 2, 2) = dicJAN(r(i + 2, 1))</span><br />
<span class="VBA_Tab2">Next i</span><br />
<br />
<span class="VBA_Tab1">Range(Sheets(2).Cells(1, 1), Sheets(2).Cells(dicJAN.Count + 1, 2)) = r</span><br />
<br />
<span class="VBA_Tab1"><span class="VBA_Comment0">’終了時間の記載</span></span><br />
<span class="VBA_Tab1">Debug.Print &#8220;Dictionaryで項目入力終了-&#8221; &#038; Time</span><br />
<br />
End Sub</div>
<p>この方法で当初コードを書いていたのですが、Keys一覧の出力がものすごく遅くて悲しくなります。<br />
せっかく連想配列を使用しているのが台無しになるレベルでした。</p>
<p>そのため、次の方法を検討してみました。</p>
<h2><span id="toc4">連想配列のキー一覧を出力する方法②-通常の配列を使用する</span></h2>
<p>連想配列を使用する一番の理由は重複を判定するメソッドがあることですので、こちらを活用してキーを別の配列に格納する方法を考えました。</p>
<p>具体的にはキーとアイテムを連想配列に格納するタイミングで、キーを別の配列に格納しておいて、後でキーを格納した配列を呼び出すというフローです。</p>
<div class="VBACode">Sub Dictionaryでキーを配列に格納してから一覧取得()<br />
<br />
<span class="VBA_Tab1"><span class="VBA_Comment0">’開始時間の記載</span></span><br />
<span class="VBA_Tab1">Debug.Print &#8220;配列で項目出力開始-&#8221; &#038; Time</span><br />
<span class="VBA_Tab1"><span class="VBA_Comment0">’Dim dicJAN</span></span><br />
<span class="VBA_Tab1"><span class="VBA_Comment0">’Set dicJAN = CreateObject(&#8220;Scripting.Dictionary&#8221;)</span></span><br />
<br />
<span class="VBA_Tab1">Dim dicJAN As New Scripting.Dictionary</span><br />
<span class="VBA_Tab1">Dim x</span><br />
<span class="VBA_Tab1">x = 0</span><br />
<span class="VBA_Tab1">Dim JANコード一覧()</span><br />
<br />
<span class="VBA_Tab1"><span class="VBA_Comment0">’JAN と金額の合計をDictionaryに格納</span></span><br />
<span class="VBA_Tab1">Dim y, i</span><br />
<span class="VBA_Tab1">With Sheets(1)</span><br />
<span class="VBA_Tab2">y = .Cells(Rows.Count, 1).End(xlUp).Row</span><br />
<span class="VBA_Tab2">For i = 2 To y</span><br />
<span class="VBA_Tab3"><span class="VBA_Comment0">’JANコードの登録がない場合、Dictionaryに追加、JANコード一覧に登録</span></span><br />
<span class="VBA_Tab3">If Not dicJAN.Exists(.Cells(i, 1).Value) Then</span><br />
<span class="VBA_Tab4">dicJAN.Add .Cells(i, 1).Value, .Cells(i, 5)</span><br />
<br />
<span class="VBA_Tab4"><span class="VBA_Comment0">’キーを「JANコード一覧」配列に格納</span></span><br />
<span class="VBA_Tab4"><span class="marker-under">ReDim Preserve JANコード一覧(x)</span></span><br />
<span class="VBA_Tab4"><span class="marker-under">JANコード一覧(x) = .Cells(i, 1).Value</span></span><br />
<span class="VBA_Tab4"><span class="marker-under">x = x + 1</span></span><br />
<br />
<span class="VBA_Tab3"><span class="VBA_Comment0">’JANコードの登録がある場合、Dictionaryに格納されている値を更新</span></span><br />
<span class="VBA_Tab3">Else</span><br />
<span class="VBA_Tab4">dicJAN(.Cells(i, 1).Value) = dicJAN(.Cells(i, 1).Value) + .Cells(i, 5)</span><br />
<span class="VBA_Tab3">End If</span><br />
<span class="VBA_Tab2">Next i</span><br />
<span class="VBA_Tab1">End With</span><br />
<br />
<span class="VBA_Tab1"><span class="VBA_Comment0">’JAN一覧B列に合計金額の出力</span></span><br />
<span class="VBA_Tab1">With Sheets(2)</span><br />
<span class="VBA_Tab2">For i = 0 To dicJAN.Count － 1</span><br />
<span class="VBA_Tab3"><span class="marker-under">.Cells(i + 2, 1) = JANコード一覧(i)</span></span><br />
<span class="VBA_Tab3">.Cells(i + 2, 2) = dicJAN(.Cells(i + 2, 1).Value)</span><br />
<span class="VBA_Tab2">Next i</span><br />
<span class="VBA_Tab1">End With</span><br />
<br />
<span class="VBA_Tab1"><span class="VBA_Comment0">’終了時間の記載</span></span><br />
<span class="VBA_Tab1">Debug.Print &#8220;配列で項目出力終了-&#8221; &#038; Time</span><br />
<br />
End Sub</div>
<p>こちらのコードを実行すると明らかに先ほどのコードよりも高速なことが確認できました。<br />
連想配列のキーを取り出す必要がある場合、別の配列にキーの一覧を格納して取得するフローが一番高速になると思います。</p>
<table border=1>
<tr>
<th align=center>キー入力速度比較</th>
<th align=center>Dictionary-Keys使用</th>
<th align=center>配列使用</th>
</tr>
<tr>
<td align=center>1回目</td>
<td align=center>0:00:39</td>
<td align=center>0:00:04</td>
</tr>
<tr>
<td align=center>2回目</td>
<td align=center>0:00:38</td>
<td align=center>0:00:04</td>
</tr>
<tr>
<td align=center>3回目</td>
<td align=center>0:00:40</td>
<td align=center>0:00:04</td>
</tr>
<tr>
<td align=center>平均</td>
<td align=center>0:00:39</td>
<td align=center>0:00:04</td>
</tr>
</table>
<h2><span id="toc5">連想配列を使用する際の最速の処理方法について</span></h2>
<p>キーを取り出す場合以外に、①連想配列にキーとアイテムを格納する際や、②連想配列の一覧を出力する際も配列を使用することでより高速化することが可能です。</p>
<p>使用するのはセルを二次元配列に格納して一気に値を取得・値を入力する方法になります<br />
興味がある方は<a href="https://officevba.info/cellstoarray/" target="_blank">こちらのページ</a>をご参照ください。</p>
<p>今回の処理においては1秒以下の実行時間まで短縮できました。<br />
セルを配列に格納する方法は慣れればすごく有効な手段になりますので、使いこなせるならぜひ覚えていただくのをおすすめします。</p>
<div class="VBACode">Sub Dictionaryを使用する際に配列を使って最速の処理()<br />
<br />
<span class="VBA_Tab1"><span class="VBA_Comment0">’セルを配列に格納した後にDicrionaryに登録・セルへの入力も配列に格納したものを一気に入力</span></span><br />
<br />
<span class="VBA_Tab1"><span class="VBA_Comment0">’開始時間の記載</span></span><br />
<span class="VBA_Tab1">Debug.Print &#8220;配列と連想配列最速開始-&#8221; &#038; Time</span><br />
<span class="VBA_Tab1"><span class="VBA_Comment0">’Dim dicJAN</span></span><br />
<span class="VBA_Tab1"><span class="VBA_Comment0">’Set dicJAN = CreateObject(&#8220;Scripting.Dictionary&#8221;)</span></span><br />
<br />
<span class="VBA_Tab1">Dim dicJAN As New Scripting.Dictionary</span><br />
<span class="VBA_Tab1">Dim x</span><br />
<span class="VBA_Tab1">x = 0</span><br />
<span class="VBA_Tab1">Dim JANコード一覧()</span><br />
<span class="VBA_Tab1">Dim y, i</span><br />
<br />
<span class="VBA_Tab1"><span class="VBA_Comment0">’JAN と金額の合計をDictionaryに格納</span></span><br />
<span class="VBA_Tab1"><span class="marker-under">Dim 参照範囲</span></span><br />
<span class="VBA_Tab1">y = Sheets(1).Cells(Rows.Count, 1).End(xlUp).Row</span><br />
<span class="VBA_Tab1"><span class="marker-under">参照範囲 = Range(Sheets(1).Cells(1, 1), Sheets(1).Cells(y, 5))</span></span><br />
<br />
<span class="VBA_Tab1">For i = 2 To y</span><br />
<span class="VBA_Tab2"><span class="VBA_Comment0">’JANコードの登録がない場合、Dictionaryに追加、JANコード一覧に登録</span></span><br />
<span class="VBA_Tab2">If Not dicJAN.Exists(参照範囲(i, 1)) Then</span><br />
<span class="VBA_Tab3">dicJAN.Add 参照範囲(i, 1), 参照範囲(i, 5)</span><br />
<br />
<span class="VBA_Tab3"><span class="VBA_Comment0">’キーを「JANコード一覧」配列に格納</span></span><br />
<span class="VBA_Tab3">ReDim Preserve JANコード一覧(x)</span><br />
<span class="VBA_Tab3">JANコード一覧(x) = 参照範囲(i, 1)</span><br />
<span class="VBA_Tab3">x = x + 1</span><br />
<br />
<span class="VBA_Tab2"><span class="VBA_Comment0">’JANコードの登録がある場合、Dictionaryに格納されている値を更新</span></span><br />
<span class="VBA_Tab2">Else</span><br />
<span class="VBA_Tab3">dicJAN(参照範囲(i, 1)) = dicJAN(参照範囲(i, 1)) + 参照範囲(i, 5)</span><br />
<span class="VBA_Tab2">End If</span><br />
<span class="VBA_Tab1">Next i</span><br />
<br />
<span class="VBA_Tab1"><span class="VBA_Comment0">’JAN一覧B列に合計金額の出力</span></span><br />
<span class="VBA_Tab1">Dim 入力範囲</span><br />
<span class="VBA_Tab1"><span class="marker-under">入力範囲 = Range(Sheets(2).Cells(1, 1), Sheets(2).Cells(dicJAN.Count + 1, 2))</span></span><br />
<br />
<span class="VBA_Tab2">For i = 0 To dicJAN.Count － 1</span><br />
<span class="VBA_Tab3">入力範囲(i + 2, 1) = JANコード一覧(i)</span><br />
<span class="VBA_Tab3">入力範囲(i + 2, 2) = dicJAN(入力範囲(i + 2, 1))</span><br />
<span class="VBA_Tab2">Next i</span><br />
<br />
<span class="VBA_Tab1"><span class="marker-under">Range(Sheets(2).Cells(1, 1), Sheets(2).Cells(dicJAN.Count + 1, 2)) = 入力範囲</span></span><br />
<br />
<span class="VBA_Tab1"><span class="VBA_Comment0">’終了時間の記載</span></span><br />
<span class="VBA_Tab1">Debug.Print &#8220;配列と連想配列最速終了-&#8221; &#038; Time</span><br />
<br />
End Sub</div>
]]></content:encoded>
					
					<wfw:commentRss>https://officevba.info/dictionary-keys/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>文字列を切り離して配列に格納する方法</title>
		<link>https://officevba.info/split-function/</link>
					<comments>https://officevba.info/split-function/#respond</comments>
		
		<dc:creator><![CDATA[okumasahito]]></dc:creator>
		<pubDate>Sat, 12 Oct 2019 04:02:44 +0000</pubDate>
				<category><![CDATA[配列]]></category>
		<category><![CDATA[関数]]></category>
		<guid isPermaLink="false">http://officevba.info/?p=1850</guid>

					<description><![CDATA[目次 配列→文字列、文字列→配列の変換はどちらも覚えると便利文字列→配列の変換にはSplit関数を用いる 配列→文字列、文字列→配列の変換はどちらも覚えると便利 以前にこちらの記事で配列を区切り文字で区切った文字列に変換 [&#8230;]]]></description>
										<content:encoded><![CDATA[
  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-6" checked><label class="toc-title" for="toc-checkbox-6">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">配列→文字列、文字列→配列の変換はどちらも覚えると便利</a></li><li><a href="#toc2" tabindex="0">文字列→配列の変換にはSplit関数を用いる</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">配列→文字列、文字列→配列の変換はどちらも覚えると便利</span></h2>
<p>以前に<a href="https://officevba.info/joinfunction_uboundfunction/" target="_blank">こちらの記事</a>で配列を区切り文字で区切った文字列に変換するJoin関数をご紹介しましたが、逆に文字列を区切って配列に格納する関数の存在を最近知りました。</p>
<p>どちらも使えるとより便利になることに気づいたのでご紹介します。</p>
<h2><span id="toc2">文字列→配列の変換にはSplit関数を用いる</span></h2>
<p>Split関数は文字列を特定の文字で切り離して、切り離した文字列をそれぞれ配列に格納するという関数です。</p>
<p>例えば誰かが作った住所録などで「郵便番号」「住所」「電話番号」が記載されていたとして、それぞれの情報が半角スペースで区切られた文字列になっているような場合、Split関数を使用すれば3つの情報を切り離して別のセルに格納することができます。</p>
<div class="VBACode">Sub Split関数で配列に格納()<br />
<br />
<span class="VBA_Tab1">Dim 住所連絡先 As String</span><br />
<span class="VBA_Tab2">住所連絡先 = &#8220;〒590-0504 大阪府泉南市信達市場 072-000-0000&#8221;</span><br />
<br />
<span class="VBA_Tab1">Dim 住所配列</span><br />
<span class="VBA_Tab2">住所配列 = Split(住所連絡先, &#8221; &#8220;)</span><br />
<span class="VBA_Tab1">MsgBox 住所配列(1)</span><br />
<br />
End Sub</div>
<p>上記のコードを実行すると住所連絡先の文字列から、「郵便番号」「住所」「電話番号」がそれぞれ配列の住所配列(0)、住所配列(1)、住所配列(2)に格納されます。</p>
<p>Excelの区切り位置指定でも似たような作業をすることができますが、例えば上記のように住所の部分だけ取り出す場合などは圧倒的にSplit関数を使う方が早いと思います。</p>
<p>また、Split関数を使用する際の注意点ですが、格納するための配列はVariant型の変数で宣言する必要があります。<br />
文字列型の配列などで宣言しても使えませんのでご注意ください。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://officevba.info/split-function/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Array関数を用いて配列に一括でデータ格納</title>
		<link>https://officevba.info/arrayfunction/</link>
					<comments>https://officevba.info/arrayfunction/#respond</comments>
		
		<dc:creator><![CDATA[okumasahito]]></dc:creator>
		<pubDate>Fri, 18 May 2018 13:47:54 +0000</pubDate>
				<category><![CDATA[配列]]></category>
		<guid isPermaLink="false">http://officevba.info/?p=1439</guid>

					<description><![CDATA[目次 配列を使うことでマクロの作成が時短になる配列へのデータの格納①一般的な格納方法②Array関数を用いた格納方法 配列を使うことでマクロの作成が時短になる 私もまだまだ使いこなせていませんが、配列はかなり便利です。  [&#8230;]]]></description>
										<content:encoded><![CDATA[
  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-8" checked><label class="toc-title" for="toc-checkbox-8">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">配列を使うことでマクロの作成が時短になる</a></li><li><a href="#toc2" tabindex="0">配列へのデータの格納</a><ol><li><a href="#toc3" tabindex="0">①一般的な格納方法</a></li><li><a href="#toc4" tabindex="0">②Array関数を用いた格納方法</a></li></ol></li></ol>
    </div>
  </div>

<h2><span id="toc1">配列を使うことでマクロの作成が時短になる</span></h2>
<p>私もまだまだ使いこなせていませんが、配列はかなり便利です。</p>
<p>私は特にVBAのコードをわかりやすくするために配列をよく使います。<br />
配列を用いることで、長く続く処理をFor~Nextなどの繰り返し処理に変更し、短くわかりやすいコードが作成できます。</p>
<p>今回はArray関数を用いて配列にデータを一括で格納する方法とサンプルコードをご紹介します。</p>
<h2><span id="toc2">配列へのデータの格納</span></h2>
<h3><span id="toc3">①一般的な格納方法</span></h3>
<p>配列の一般的な使い方は下記のようになります。</p>
<p>変数と同じく宣言をしますが、変数との違いはインデックス番号を()で囲んでいくつのデータを含むかを記載します。<br />
インデックス番号は「0」から始まるので、例えば下記のように「5」と宣言すると6個のデータを格納できる配列となります。</p>
<div class="VBACode">Dim Fruits(5) As String<br />
Fruits(0) = &#8220;みかん&#8221;<br />
Fruits(1) = &#8220;りんご&#8221;<br />
Fruits(2) = &#8220;いちご&#8221;<br />
Fruits(3) = &#8220;もも&#8221;<br />
Fruits(4) = &#8220;ぶどう&#8221;<br />
Fruits(5) = &#8220;バナナ&#8221;</div>
<p>今回は文字列のString型で宣言していますが、他の型で宣言したり、Variant型で宣言することもできます。</p>
<h3><span id="toc4">②Array関数を用いた格納方法</span></h3>
<p>一般的なデータの格納方法はデータが増えると行数が増えて対応しにくいのですが、Array関数を用いることで行数を減らすことができます。</p>
<div class="VBACode">Dim Fruits As Variant<br />
Fruits = Array(&#8220;みかん&#8221;, &#8220;りんご&#8221;, &#8220;いちご&#8221;, &#8220;もも&#8221;, &#8220;ぶどう&#8221;, &#8220;バナナ&#8221;)</div>
<p>Array関数を用いてデータを格納する際の注意点としては、バリアント型の変数として宣言しておかないとエラーになることです。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://officevba.info/arrayfunction/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>配列の要素を取り出す関数について</title>
		<link>https://officevba.info/joinfunction_uboundfunction/</link>
					<comments>https://officevba.info/joinfunction_uboundfunction/#respond</comments>
		
		<dc:creator><![CDATA[okumasahito]]></dc:creator>
		<pubDate>Wed, 18 Apr 2018 14:43:43 +0000</pubDate>
				<category><![CDATA[配列]]></category>
		<category><![CDATA[関数]]></category>
		<guid isPermaLink="false">http://officevba.info/?p=1365</guid>

					<description><![CDATA[目次 配列の要素を取り出す専用の関数がある関数を使わず配列の要素を取り出すサンプルコードUBound関数を使用した場合のサンプルコードJoin関数を使用した場合のサンプルコード 配列の要素を取り出す専用の関数がある 以前 [&#8230;]]]></description>
										<content:encoded><![CDATA[
  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-10" checked><label class="toc-title" for="toc-checkbox-10">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">配列の要素を取り出す専用の関数がある</a></li><li><a href="#toc2" tabindex="0">関数を使わず配列の要素を取り出すサンプルコード</a></li><li><a href="#toc3" tabindex="0">UBound関数を使用した場合のサンプルコード</a></li><li><a href="#toc4" tabindex="0">Join関数を使用した場合のサンプルコード</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">配列の要素を取り出す専用の関数がある</span></h2>
<p>以前から配列の値を取り出すのに良い方法が思いつかなかったので、結構力技で実施していたのですが、配列を取り出すのに便利な関数があることを知ってショックを受けました。</p>
<p>今回は配列の要素を取り出す際に役立つJoin関数とUBound関数をご紹介します。</p>
<h2><span id="toc2">関数を使わず配列の要素を取り出すサンプルコード</span></h2>
<p>これまで私が配列を取り出す際に使用していたコードは以下のようなものになります。</p>
<p>ExcelでA列のセルの値を配列に格納し、その配列の要素を取り出すサンプルコードです。<br />
配列の要素数は可変を想定してコードを作成しています。</p>
<div class="VBACode">Sub 配列の要素取り出し()<br />
<br />
<span class="VBA_Tab1">Dim hairetsu()</span><br />
<span class="VBA_Tab1">Dim i As Long, k As Long</span><br />
<span class="VBA_Tab1">k = 0</span><br />
<span class="VBA_Tab1">i = 0</span><br />
<span class="VBA_Tab1">Do Until Cells(i + 1, 1) = &#8220;&#8221;</span><br />
<span class="VBA_Tab2">ReDim Preserve hairetsu(i)</span><br />
<span class="VBA_Tab2">hairetsu(i) = Cells(i + 1, 1)</span><br />
<span class="VBA_Tab2">k = k + 1</span><br />
<span class="VBA_Tab1">i = i + 1</span><br />
<span class="VBA_Tab1">Loop</span><br />
<br />
<span class="VBA_Tab1">Dim mojiretsu</span><br />
<span class="VBA_Tab1">mojiretsu = hairetsu(0)</span><br />
<span class="VBA_Tab1">For i = 1 To k &#8211; 1</span><br />
<span class="VBA_Tab2">mojiretsu = mojiretsu &#038; &#8220;,&#8221; &#038; hairetsu(i)</span><br />
<span class="VBA_Tab1">Next i</span><br />
<span class="VBA_Tab1">MsgBox mojiretsu</span><br />
<br />
End Sub</div>
<p>要素数を調べるために変数kを宣言し、iと同じ数になるようにして呼び出す際に使用しています。</p>
<p>このコードはきちんと動作するのですが、以下2点の手間・問題点がありました。</p>
<li>①要素数で繰り返し処理をする際、変数kに最後に余分に追加された1を減らすのがややこしくて面倒</li>
<li>②変数を文字列にする際に間に入れる文字（今回は”,”）は要素数-1の数を繰り返して挿入するため、配列の1つめかもしくは最終だけは繰り返しの中で処理できない</li>
<p>これらの問題点はUBound関数やJoin関数を使えばきちんと解決できます。</p>
<h2><span id="toc3">UBound関数を使用した場合のサンプルコード</span></h2>
<p>Ubound関数は配列の要素数を返す関数です。<br />
（配列のインデックス番号を返すので厳密には要素数-1となります。）</p>
<p>この関数を知って、これまで私が要素数の確認のためにわざわざ宣言して使用していた変数kが必要ないことがわかりました。<br />
Ubound関数を使用すると要素を文字列にするのが少し簡略化されます。</p>
<div class="VBACode">Sub 配列の要素取り出しUBound関数使用()<br />
<br />
<span class="VBA_Tab1">Dim hairetsu()</span><br />
<span class="VBA_Tab1">Dim i As Long</span><br />
<span class="VBA_Tab1">i = 0</span><br />
<span class="VBA_Tab1">Do Until Cells(i + 1, 1) = &#8220;&#8221;</span><br />
<span class="VBA_Tab2">ReDim Preserve hairetsu(i)</span><br />
<span class="VBA_Tab2">hairetsu(i) = Cells(i + 1, 1)</span><br />
<span class="VBA_Tab1">i = i + 1</span><br />
<span class="VBA_Tab1">Loop</span><br />
<br />
<span class="VBA_Tab1">Dim mojiretsu</span><br />
<span class="VBA_Tab1">mojiretsu = hairetsu(0)</span><br />
<span class="VBA_Tab1">For i = 1 To UBound(hairetsu)</span><br />
<span class="VBA_Tab2">mojiretsu = mojiretsu &#038; &#8220;,&#8221; &#038; hairetsu(i)</span><br />
<span class="VBA_Tab1">Next i</span><br />
<span class="VBA_Tab1">MsgBox mojiretsu</span><br />
<br />
End Sub</div>
<h2><span id="toc4">Join関数を使用した場合のサンプルコード</span></h2>
<p>Join関数は配列の要素を文字列の一覧として取り出す関数です。<br />
Join(“配列名”,”区切りに使用する文字列”)の形式で要素を文字列に変換して並べることが可能です。</p>
<p>区切りの文字を”<br />”やVbCr、VbCrLfにすることで改行コードを間にはさむことも可能です。</p>
<p>細かい部分の融通は利きにくいかもしれませんが、簡単に間に文字列を挟み込むことができるので使用しやすいです。</p>
<div class="VBACode">Sub 配列の要素取り出しJoin関数使用()<br />
<br />
<span class="VBA_Tab1">Dim hairetsu()</span><br />
<span class="VBA_Tab1">Dim i As Long, k As Long</span><br />
<span class="VBA_Tab1">i = 0</span><br />
<span class="VBA_Tab1">Do Until Cells(i + 1, 1) = &#8220;&#8221;</span><br />
<span class="VBA_Tab2">ReDim Preserve hairetsu(i)</span><br />
<span class="VBA_Tab2">hairetsu(i) = Cells(i + 1, 1)</span><br />
<span class="VBA_Tab1">i = i + 1</span><br />
<span class="VBA_Tab1">Loop</span><br />
<br />
<span class="VBA_Tab1">Dim mojiretsu</span><br />
<span class="VBA_Tab1">mojiretsu = Join(hairetsu, &#8220;,&#8221;)</span><br />
<span class="VBA_Tab1">MsgBox mojiretsu</span><br />
<br />
End Sub</div>
]]></content:encoded>
					
					<wfw:commentRss>https://officevba.info/joinfunction_uboundfunction/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>ExcelVBAでセルを配列に入れて高速化</title>
		<link>https://officevba.info/cellstoarray/</link>
					<comments>https://officevba.info/cellstoarray/#respond</comments>
		
		<dc:creator><![CDATA[okumasahito]]></dc:creator>
		<pubDate>Sat, 28 Oct 2017 14:24:36 +0000</pubDate>
				<category><![CDATA[マクロの処理時間の短縮]]></category>
		<category><![CDATA[配列]]></category>
		<category><![CDATA[ExcelVBA]]></category>
		<category><![CDATA[高速化]]></category>
		<guid isPermaLink="false">http://officevba.info/?p=1177</guid>

					<description><![CDATA[目次 セルへの値の代入は時間がかかるセルを配列に入れてスピードアップできる例所要時間の計測セルの配列への代入における注意点①セルの値を格納するために宣言する変数（配列）はバリアント型②配列のインデックス番号は1から③セル [&#8230;]]]></description>
										<content:encoded><![CDATA[
  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-12" checked><label class="toc-title" for="toc-checkbox-12">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">セルへの値の代入は時間がかかる</a></li><li><a href="#toc2" tabindex="0">セルを配列に入れてスピードアップできる例</a></li><li><a href="#toc3" tabindex="0">所要時間の計測</a></li><li><a href="#toc4" tabindex="0">セルの配列への代入における注意点</a><ol><li><a href="#toc5" tabindex="0">①セルの値を格納するために宣言する変数（配列）はバリアント型</a></li><li><a href="#toc6" tabindex="0">②配列のインデックス番号は1から</a></li><li><a href="#toc7" tabindex="0">③セルの値以外は変更できない</a></li></ol></li></ol>
    </div>
  </div>

<h2><span id="toc1">セルへの値の代入は時間がかかる</span></h2>
<p>対象となるセルが少なければ問題は起こらないのですが、たくさんのセルに対して条件分岐を加えながらセルの値を変更しようとするとかなり時間がかかってしまい、他の操作と合わせた一連のマクロの中で律速になってしまうことがあります。</p>
<p>今回はそんなときに大活躍のセルを配列に入れるVBAコードを紹介します。</p>
<h2><span id="toc2">セルを配列に入れてスピードアップできる例</span></h2>
<p>例えば仮に以下のシートのようにセルの縦10000行、横1000列のセルにランダムな0～9までの整数が入っているシートがあったと仮定して、これらのセルの中で値が「0」のものを空白にするマクロを作るとします。</p>
<p><a href="https://officevba.info/wp-content/uploads/2017/10/80-1.jpg"><img decoding="async" src="https://officevba.info/wp-content/uploads/2017/10/80-1-300x160.jpg" alt="80-1" width="300" height="160" class="alignnone size-medium wp-image-1180" srcset="https://officevba.info/wp-content/uploads/2017/10/80-1-300x160.jpg 300w, https://officevba.info/wp-content/uploads/2017/10/80-1-768x410.jpg 768w, https://officevba.info/wp-content/uploads/2017/10/80-1-700x374.jpg 700w, https://officevba.info/wp-content/uploads/2017/10/80-1-320x171.jpg 320w, https://officevba.info/wp-content/uploads/2017/10/80-1.jpg 1920w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>
<p>その際に最も簡単な手順でVBAコードを作成すると以下のようになると思います。</p>
<div class="VBACode">Sub セルの値を0から空白にする()<br />
<br />
<span class="VBA_Tab1">Dim 開始時間 As Date, 終了時間 As Date</span><br />
<span class="VBA_Tab1">Dim i As Long, k As Long</span><br />
<br />
<span class="VBA_Tab1">開始時間 = Timer <span class="VBA_Comment">’時間の計測</span></span><br />
<span class="VBA_Tab1">Application.ScreenUpdating = False</span><br />
<span class="VBA_Tab1">For i = 1 To 10000</span><br />
<span class="VBA_Tab2">For k = 1 To 1000</span><br />
<span class="VBA_Tab3">If Cells(i, k) = 0 Then</span><br />
<span class="VBA_Tab4">Cells(i, k) = &#8220;&#8221;</span><br />
<span class="VBA_Tab3">End If</span><br />
<span class="VBA_Tab2">Next k</span><br />
<span class="VBA_Tab1">Next i</span><br />
<span class="VBA_Tab1">Application.ScreenUpdating = True</span><br />
<span class="VBA_Tab1">終了時間 = Timer <span class="VBA_Comment">’時間の計測</span></span><br />
<span class="VBA_Tab1">Debug.Print Round(終了時間 &#8211; 開始時間, 3)  <span class="VBA_Comment">’所要時間を書き出す</span></span><br />
<br />
End Sub</div>
<p>このVBAコードはそれぞれのセルに対してすべて個別に値を取得し、条件に一致するものの値を削除する手順を行うため、とても時間がかかる処理になってしまいます。</p>
<p>そこでこのコードを以下のように変更すると劇的に処理速度がアップします。</p>
<div class="VBACode">Sub セルを配列に入れて0の値を空欄にする()<br />
<br />
<span class="VBA_Tab1">Dim 開始時間 As Date, 終了時間 As Date</span><br />
<span class="VBA_Tab1">Dim i As Long, k As Long</span><br />
<span class="VBA_Tab1">Dim c As Variant</span><br />
<br />
<span class="VBA_Tab1">開始時間 = Timer <span class="VBA_Comment">’時間の計測</span></span><br />
<span class="VBA_Tab1">Application.ScreenUpdating = False</span><br />
<span class="VBA_Tab1">c = Range(Cells(1, 1), Cells(10000, 1000))</span><br />
<span class="VBA_Tab1">For i = 1 To 10000</span><br />
<span class="VBA_Tab2">For k = 1 To 1000</span><br />
<span class="VBA_Tab3">If c(i, k) = 0 Then</span><br />
<span class="VBA_Tab4">c(i, k) = &#8220;&#8221;</span><br />
<span class="VBA_Tab3">End If</span><br />
<span class="VBA_Tab2">Next k</span><br />
<span class="VBA_Tab1">Next i</span><br />
<span class="VBA_Tab1">Range(Cells(1, 1), Cells(10000, 1000)) = c</span><br />
<br />
<span class="VBA_Tab1">Application.ScreenUpdating = True</span><br />
<span class="VBA_Tab1">終了時間 = Timer <span class="VBA_Comment">’時間の計測</span></span><br />
<span class="VBA_Tab1">Debug.Print Round(終了時間 &#8211; 開始時間, 3) <span class="VBA_Comment">’所要時間を書き出す</span></span><br />
<br />
End Sub</div>
<p>このVBAコードはバリアント型の変数を宣言して複数のセルを代入することで、それぞれのセルの値を配列として処理できるようにしたものです。</p>
<p>配列の値の変更はセル自体の値の変更よりも圧倒的に早く、セルに値を戻すのは一括で処理できるため処理速度が上がるという仕組みです。<br />
（日本語変だったらすみません。あまり意味は分からなくてもとりあえずVBAコードが使用できればそれでも良い気がします。）</p>
<h2><span id="toc3">所要時間の計測</span></h2>
<p>それぞれのコードについて、10回実行した際の所要時間を以下に記載します。</p>
<table>
<thead>
<tr>
<th>回数</th>
<th>配列使用しない</th>
<th>配列使用</th>
</tr>
</thead>
<tbody>
<tr>
<td>1回目</td>
<td>58.5(秒)</td>
<td>11.8(秒)</td>
</tr>
<tr>
<td>2回目</td>
<td>247.5(秒)</td>
<td>11.8(秒)</td>
</tr>
<tr>
<td>3回目</td>
<td>58.6(秒)</td>
<td>11.8(秒)</td>
</tr>
<tr>
<td>4回目</td>
<td>59(秒)</td>
<td>11.8(秒)</td>
</tr>
<tr>
<td>5回目</td>
<td>247.1(秒)</td>
<td>11.8(秒)</td>
</tr>
<tr>
<td>6回目</td>
<td>247.1(秒)</td>
<td>11.9(秒)</td>
</tr>
<tr>
<td>7回目</td>
<td>248.7(秒)</td>
<td>11.9(秒)</td>
</tr>
<tr>
<td>8回目</td>
<td>53.2(秒)</td>
<td>11.8(秒)</td>
</tr>
<tr>
<td>9回目</td>
<td>56.1(秒)</td>
<td>11.7(秒)</td>
</tr>
<tr>
<td>10回目</td>
<td>55.8(秒)</td>
<td>11.9(秒)</td>
</tr>
<tr>
<td>平均</td>
<td>133.2(秒)</td>
<td>11.8(秒)</td>
</tr>
</tbody>
</table>
<p>配列に格納する処理がいかに高速かわかると思います。</p>
<p>また、通常の処理は負荷が大きいのか、処理時間が2パターンに分かれて計測されました。<br />
配列を使用した方は安定した処理速度が期待できるのも大きなメリットです。</p>
<h2><span id="toc4">セルの配列への代入における注意点</span></h2>
<p>セルを配列に入れる際の注意点は以下の3点です。</p>
<h3><span id="toc5">①セルの値を格納するために宣言する変数（配列）はバリアント型</span></h3>
<p>セルの値を格納する配列はRange型ではなくバリアント型を宣言します。</p>
<h3><span id="toc6">②配列のインデックス番号は1から</span></h3>
<p>配列のインデックス番号は通常0からスタートしますが、セルを格納した配列に関しては1がインデックス番号の開始番号となります。<br />
私はこの部分に違和感を感じ、なじむのに時間がかかりました。</p>
<h3><span id="toc7">③セルの値以外は変更できない</span></h3>
<p>配列に格納しているのはセルの値のみのため、セルの背景色やフォントなどの情報は配列に格納されないので値以外の変更には使用できません。<br />
（と思います。できたらすみません。）</p>
]]></content:encoded>
					
					<wfw:commentRss>https://officevba.info/cellstoarray/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
