リストのリスト
Last updated
Last updated
ここでは、階層にもう 1 つの層を追加してみましょう。「リストの操作」の章で例として取り上げたトランプを、ここでも例として使用します。たとえば、複数のデッキ(デッキとは 1 組のトランプのこと)が含まれたボックスを作成したとすると、そのボックスはデッキを格納するリストで、各デッキはカードのリストということになります。これが、「リストのリスト」という考え方です。たとえば次の図では、硬貨の山のリストが入っていて、それぞれの山には硬貨のリストが含まれています。
写真: Dori
リストのリストに関する質問(クエリー)を作成する場合、次のような質問が考えられます。これにより、リストの特性(プロパティ)がわかります。
Q: 硬貨は何種類?A: 2.
Q: 硬貨のタイプ値は? A: $0.01 と $0.25 です。
Q: 25 セント硬貨の材質は?A: 銅 75%、ニッケル 25%
Q: 1 セント硬貨の材質は?A: 亜鉛 97.5%、銅 2.5%
リストのリストに対して実行できる操作(アクション)としては、次のような操作が考えられます。この場合、実行する操作に応じてリストのリストが変化します。
25 セント硬貨または 1 セント硬貨の特定の山を選ぶ。
特定の 25 セント硬貨または 1 セント硬貨を選ぶ。
25 セント硬貨の山と 1 セント硬貨の山の配置を変える。
25 セント硬貨の山と 1 セント硬貨の山をすべて入れ替える。
前の章でも説明したように、Dynamo の各ノードを使用して、上記の操作に似た操作を実行することができます。ここでは、物理的な物体ではなく抽象的なデータを操作するため、データ階層を上下に移動する方法をコントロールするための一連のルールが必要になります。
リストのリストを操作する場合、データは複雑な階層構造になっていますが、この複雑な構造により、非常に高度なパラメータ操作を実行することができます。これ以降の各演習では、基礎的な概念といくつかの操作方法を確認していきます。
下のリンクをクリックして、サンプル ファイルをダウンロードします。
すべてのサンプル ファイルの一覧については、付録を参照してください。
このセクションで説明する基本的な概念は、「Dynamo は、リストをオブジェクトとして処理する」ということです。トップダウン階層は、オブジェクト指向プログラミングをベースとして開発されています。Dynamo は、List.GetItemAtIndex などのコマンドでサブ要素を選択するのではなく、データ構造内でメイン リストのインデックスを選択します。リスト中で選択したその項目が、別のリストである場合もあります。ここからは、サンプルの図を使用して詳しく説明していきます。
Code Block ノードを使用して、
0..2; 0..3;
という 2 つの範囲が定義されています。これらの範囲は、レーシングが「外積」に設定された Point.ByCoordinates ノードに接続されています。これにより、点のグリッドが作成され、リストのリストが出力として返されます。
Watch ノードの各リストで、4 つの項目を持つ 3 つのリストが指定されていることに注意してください。
インデックス値 0 を指定して List.GetItemAtIndex ノードを使用した場合、Dynamo は、最初のリストとそのリスト内のすべてのコンテンツを選択します。他のプログラムでは、データ構造内のすべてのリストの最初の項目だけが選択される場合がありますが、Dynamo は、トップダウン階層を使用してデータの処理を行います。
下のリンクをクリックして、サンプル ファイルをダウンロードします。
すべてのサンプル ファイルの一覧については、付録を参照してください。
フラット化を行うと、データ構造からすべてのデータ層が削除されます。この機能は、操作にデータ階層が必要ない場合に便利ですが、情報が削除される可能性があります。次の図は、データのリストをフラット化した結果を示しています。
Code Block ノードで
-250..-150..#4;
というコード行を挿入して範囲を定義します。Code Block ノードを Point.ByCoordinates ノードの x 入力と y 入力に接続します。これにより、点のグリッドを取得するための「外積」に対するレーシングが設定されます。
Watch ノードに、リストのリストが表示されます。
PolyCurve.ByPoints ノードは、各リストを参照して個別のポリカーブを作成します。Dynamo のプレビューに 4 つのポリカーブが表示されます。それぞれのポリカーブが、グリッド内の各行を表しています。
PolyCurve.ByPoints ノードの前に Flatten ノードを挿入して、すべての点を含む単一のリストを作成します。PolyCurve.ByPoints ノードは、リストを参照して 1 つのカーブを作成しますが、すべての点が 1 つのリスト上に存在しているため、点のリスト全体を通過するジグザクのポリカーブが 1 つだけ作成されます。
独立したデータ層をフラット化する方法も用意されています。List.Flatten ノードを使用すると、データ層の数を定義して、最上位の階層からデータ層をフラット化することができます。このノードは、現在のワークフローに必ずしも関係しない複雑なデータ構造を操作する場合に特に便利です。別の方法として、Flatten ノードを関数として List.Map ノードで使用することもできます。List.Map ノードの詳細については、以下で説明します。
下のリンクをクリックして、サンプル ファイルをダウンロードします。
すべてのサンプル ファイルの一覧については、付録を参照してください。
パラメトリック モデリングを行う際に、既存のリストのデータ構造を修正したい場合があります。その場合、さまざまなノードを使用できますが、List.Chop ノードが最も基本的なノードです。List.Chop ノードで設定された数の項目を使用すると、1 つのリストを複数のサブリストに分割することができます。
Chop コマンドを実行すると、指定されたリストの長さに従ってリストが分割されます。List.Chop ノードは、データ構造を削除するのではなく新しいデータ層をデータ構造に追加するなど、いくつかの点で List.Flatten ノードとは逆の動作を行います。List.Chop ノードは、次の例のようなジオメトリに関する操作を実行する場合に便利です。
下のリンクをクリックして、サンプル ファイルをダウンロードします。
すべてのサンプル ファイルの一覧については、付録を参照してください。
List.Map ノードと List.Combine ノードは、階層内の 1 段階下の層で、設定された関数を入力リストに適用します。リストの組み合わせとリストのマップはほとんど同じ操作ですが、組み合わせの場合は、特定の関数の入力に対応する複数の入力を使用できる点が、マップとは異なっています。
注: この演習は前バージョンの Dynamo を使用して作成されました。 List.Map の機能に関する問題の大半は、 List@Level _機能の追加によって解決されました。詳細については、後述の _ List@Level を参照してください。
簡単な例として、前のセクションで説明した List.Count ノードをもう一度確認してみましょう。
List.Count ノードは、リスト内のすべての項目をカウントします。ここでは、List.Count ノードを使用して、List.Map ノードの仕組みについて説明します。
Code Block ノードで、次の 2 行を挿入します。
-50..50..#Nx; -50..50..#Ny;
このコードを入力すると、Code Block ノードに Nx と Ny という 2 つの入力が作成されます。
2 つの Integer Slider ノードを使用して Nx の値と Ny の値を Code Block ノードに接続すると、これらの値が定義されます。
次に、Code Block ノードの各行を Point.ByCoordinates ノードの x 入力と y 入力に接続します。このノードを右クリックして「レーシング」と「外積」を続けて選択します。この操作により、点のグリッドが作成されます。-50 から 50 までの範囲が定義されているため、ここでは既定の Dynamo グリッド全体を使用しています。
Watch ノードに、作成された点が表示されます。データ構造を確認すると、リストのリストが作成されていることがわかります。それぞれのリストが、グリッドの点の 1 行を表しています。
前の手順の Watch ノードの出力に List.Count ノードを接続します。
Watch ノードを List.Count ノードの出力に接続します。
List.Count ノードによって 5 という値が生成されていることに注意してください。これは、Code Block ノードで定義されている「Nx」変数と同じ値です。こうなる理由は次のとおりです。
まず、Point.ByCoordinates ノードは、リストを作成するための主要な入力として「x」入力を使用します。Nx の値が 5 で Ny の値が 3 の場合、3 つの項目を持つ 5 つのリストが含まれた 1 つのリストが作成されます。
Dynamo は、リストをオブジェクトとして処理するため、List.Count ノードは、階層内のメインのリストに適用されます。その結果、メインのリストに含まれているリストの数である 5 という値が生成されることになります。
List.Map ノードを使用して、階層内の 1 段階下の層で「関数」を実行します。
List.Count ノードには入力がないことに注意してください。List.Count ノードは関数として使用されるため、このノードは階層内の 1 段階下の層にあるすべてのリストに適用されます。List.Count ノードの空の入力は、List.Map ノードの list 入力に対応しています。
List.Count ノードにより、5 つの項目を持つリストが 1 つ作成されます。それぞれの項目の値は 3 になります。この値は、各サブリストの長さを表しています。
注: この演習は前バージョンの Dynamo を使用して作成されました。List.Combine の機能に関する問題の大半は、 List@Level 機能の追加によって解決されました。詳細については、後述の List@Level を参照してください。
この演習では、List.Combine ノードを使用して、個別のオブジェクト リストに関数を適用する方法を説明します。
最初に、2 つの点のリストを設定します。
Sequence ノードを使用して 10 の値を生成し、各値に 10 のステップ増分を指定します。
結果を Point.ByCoordinates ノードの x 入力に接続します。これにより、Dynamo で点のリストが作成されます。
2 番目の Point.ByCoordinates ノードをワークスペースに追加し、x 入力として同じ Sequence 出力を使用し、y 入力として Integer Slider を使用し、その値を 31 (1 番目の点のセットと重ならない限り任意の値)に設定して、2 つの点のセットがお互いに重ならないようにします。
次に、List.Combine ノードを使用して、2 つの異なるリスト内のオブジェクトに関数を適用します。この場合、単純な線描画関数になります。
ワークスペースに List.Combine ノードを追加し、2 つの点のセットを list0 と list1 入力として接続します。
List.Combine ノードの入力関数として Line.ByStartPointEndPoint ノードを使用します。
完了すると、2 つの点のセットが Line.ByStartPointEndPoint 関数を介して一緒に圧縮またはペアリングされ、Dynamo で 10 行が返されます。
List.Combine の別の使用例については、N 次元のリストの演習を参照してください。
下のリンクをクリックして、サンプル ファイルをダウンロードします。
すべてのサンプル ファイルの一覧については、付録を参照してください。
List.Map ではなく List@Level 機能を使用すると、ノードの入力ポートに使用するリストのレベルを直接選択することができます。この機能は、入力ポートに指定されたあらゆる入力値に使用できます。使用すると、もっともすばやく簡単にリストのレベルにアクセスすることができます。ノードの入力として使用するリストのレベルを指定するだけで、後はすべてをノードに任せることができます。
この演習では、List@Level 機能を使用して特定のデータ レベルを分離してみましょう。
点によって構成される単純な 3D グリッドから始めることにします。
X、Y、Z に Range ノードを接続することでグリッドが構成されています。したがって、データの構造は X リスト、Y リスト、Z リストの 3 層から成ることがわかります。
これらの層は、異なるレベルに存在します。レベルは、プレビュー バルーンの下に表示されます。リスト レベルの列はリスト データに対応しています。ここで、作業中のレベルを確認することができます。
リスト レベルは逆順で階層化されているので、最低レベルのデータは常に「L1」にあります。これにより、上流で何かが変更されたとしても、グラフを意図したとおりに動作させることができます。
List@Level 機能を使用するには、[>]をクリックします。このメニュー内部では、2 つのチェックボックスが表示されます。
レベルを使用 - このオプションをオンにすると、List@Level の機能が有効になります。このオプションをクリックした後で、ノードで使用する入力リスト レベルをすべてクリックして選択することができます。このメニューで上矢印か下矢印をクリックすることにより、さまざまなレベル オプションを試すことができます。
リスト構造を保持 - オンにしていると、その入力のレベル構造を保持することができます。意図的にデータを複数のサブリストに整理している場合は、このオプションをオンにしておくと、いかなる情報も失わずにリスト構造をそのまま保持しておくことができます。
リスト レベル全体を切り替えることにより、単純な 3D グリッド上でリスト構造を視覚的に確認することができます。リスト レベルとインデックスの組み合わせを変更すると、元の 3D セットとは異なる点のセットが返されます。
DesignScript で「@L2」を選択すると、レベル 2 のリストのみを選択することができます。index に 0 が入力されているとき、レベル 2 のリストには Y を 0 とする点のセットのみが含まれているので、XZ のグリッド面のみが返されます。
レベル フィルタを「@L1」に変更すると、リスト レベル 1 に含まれるすべての点を確認することができます。index に 0 が入力されているとき、レベル 1 のリストにはフラット リストの 3D ポイントがすべて含まれています。
同様に「@L3」に変更すると、リスト レベル 3 の点のみが表示されます。index に 0 が入力されているとき、レベル 3 のリストには Z を 0 とする点のセットのみが含まれているので、XY のグリッド面のみが返されます。
同様に「@L4」に変更すると、リスト レベル 4 の点のみが表示されます。index に 0 が入力されているとき、レベル 4 のリストには X を 0 とする点のセットのみが含まれているので、YZ のグリッド面のみが返されます。
今回の例は List.Map でも作成できますが、List@Level を使用すると、動作を単純化して簡単にノード データにアクセスできるようになります。次に List.Map と List@Level の比較をご覧ください。
どちらの方法でも同じ点にアクセスすることができますが、List@Level を使用するとたった 1 個のノードだけでデータのレイヤを簡単に切り替えることができます。
List.Map を使用して点構成のグリッドにアクセスするには、List.Map の隣に List.GetItemAtIndex ノードを配置する必要があります。レベルの階層を下りていくたびに、List.Map ノードを追加していく必要があります。リストが複雑になればなるほど、目的の情報レベルにアクセスするには、多数の List.Map ノードをグラフに追加しなければなりません。
この例では、List.GetItemAtIndex ノードを List.Map ノードに接続することにより、List.GetItemAtIndex で「@L3」を選択したときと同じリスト構造を持つ同じ点のセットを取得しています。
下のリンクをクリックして、サンプル ファイルをダウンロードします。
すべてのサンプル ファイルの一覧については、付録を参照してください。
転置は、リストのリストを操作する場合の基本的な機能です。転置を実行すると、スプレッドシート プログラムの場合と同様に、データ構造内の列と行の位置が反転します。次の基本的な行列を使用して、転置の仕組みを説明します。また、次のセクションでは、転置機能を使用して幾何学的な関係を作成する方法について説明します。
最初に、前の演習で使用した List.Count ノードを削除して別のジオメトリに移動し、データ構造がどのようになっているかを確認します。
Point.ByCoordinates ノードから続く Watch ノードの出力に、PolyCurve.ByPoints ノードを接続します。
出力として 5 つのポリカーブが作成され、Dynamo のプレビューにそれらのポリカーブが表示されます。Dynamo ノードは点のリスト(この場合は、点のリストのリスト)を検索し、そのリストから 1 つのポリカーブを作成します。原則として、各リストはデータ構造内で曲線に変換されます。
List.Transpose ノードは、すべての項目をメイン リスト内のすべてのリストと切り替えます。この動作は少し複雑に感じるかもしれませんが、データ構造内の列と行を入れ替える Microsoft Excel と同じ仕組みです。
転置により、リストの構造が変更されていることを確認します。転置前は 3 つの項目を持つ 5 つのリストだったのに対して、転置後は 5 つの項目を持つ 3 つのリストに変わっています。
PolyCurve.ByPoints ノードにより、元の曲線に対して垂直方向に 3 つのポリカーブが作成されます。
Code Block では、「[]」という省略表記を使用してリストを定義します。この方法を使用すると、List.Create ノードを使用するよりも素早く柔軟にリストを作成することができます。Code Block の詳細は、「Code Block と DesignScript」を参照してください。次の図は、Code Block を使用して、複数の式を持つリストを作成する方法を示しています。
Code Block で「[]」という省略表記を使用すると、複雑なデータ構造で特定の項目をすばやく簡単に選択することができます。Code Block の詳細は、「Code Block と DesignScript」の章で説明しています。次の図は、Code Block を使用して、複数のデータ タイプが存在するリストのクエリーを実行する方法を示しています。
下のリンクをクリックして、サンプル ファイルをダウンロードします。
すべてのサンプル ファイルの一覧については、付録を参照してください。
この演習では、前の演習で作成したロジックを使用してサーフェスを編集します。この演習の目的は直感的な操作を行うことですが、データ構造のナビゲーションは少し複雑な操作です。ここでは、制御点を移動することにより、サーフェスの編集を行います。
最初に、上図の各ノードの文字列を操作します。既定の Dynamo グリッド全体にわたる基本的なサーフェスを作成します。
Code Block ノードを使用して次の 2 つのコード行を入力し、Surface.PointAtParameter ノードの u 入力と v 入力にそれぞれのコード行を接続します(
-50..50..#3;
と-50..50..#5;
)。Surface.PointAtParameter ノードのレーシングを「外積」に設定します。
Watch ノードに、5 つの項目を持つ 3 つのリストが含まれた 1 つのリストが表示されます。
この演習では、作成したグリッドの中心点のクエリーを実行します。これを行うには、中央のリストの中心点を選択します。
正しい点を選択するには、Watch ノードの各項目をクリックして、正しい点が選択されているかどうかを確認します。
Code Block ノードを使用して、リストのリストをクエリーするための基礎となるコード行を次の形式で指定します。
points[1][2];
Geometry.Translate ノードを使用して、選択した点を Z の正の向きに 20 単位移動します。
List.GetItemAtIndex ノードを使用して、点の中央の行を選択します。前の手順と同様に、Code Block ノードで
points[1];
というコード行を指定してクエリーを実行することもできます。
ここまでの手順で、中心点のクエリーを実行し、中心点を上方向に移動しました。ここでは、この中心点を元のデータ構造に戻します。
最初に、前の手順で分離したリストの項目を置き換えます。
List.ReplaceItemAtIndex ノードで「2」というインデックス値を使用し、置き換える項目を対象となる点(Geometry.Translate ノードの Geometry 出力)に接続して、中心点を置き換えます。
対象の点がリストの中央の項目に入力されたことが出力として表示されます。
ここでは、前の演習で変更したリストを、元のデータ構造であるリストのリストに戻します。
前の演習と同様に、List.ReplaceItemAtIndex ノードを使用して、中央のリストを変更したリストで置き換えます。
これら 2 つのノードのインデックスを定義する Code Block ノードの値は、それぞれ 1 と 2 であることに注意してください。これらの値は、Code Block ノードで指定した元のクエリー(points[1][2])に対応しています。
インデックス 1 の位置でリストを選択すると、Dynamo のプレビューでデータ構造がハイライト表示されます。これで、対象の点が元のデータ構造に正しく移動されたことになります。
上図の点のセットからサーフェスを作成する方法はいくつかあります。ここでは、複数の曲線をまとめてロフトしてサーフェスを作成してみましょう。
NurbsCurve.ByPoints ノードを作成し、新しいデータ構造を接続して、3 つの NURBS 曲線を作成します。
Surface.ByLoft ノードを NurbsCurve.ByPoints ノードの出力に接続します。これで、サーフェスが変更されました。ジオメトリの元の Z 値を変更することができます。この値を変更して、ジオメトリがどのように変化するかを確認してください。