実行時に指定された配列の次元を合計するにはどうすればよいですか?
-
09-06-2019 - |
質問
私は分布のエントロピーを確立する関数に取り組んでいます。コピュラに詳しい人がいるなら、それはコピュラを使用します。どの次元が「考慮される」かに基づいて、配列内の値を合計する必要があります。
例:次の例を考えてみましょう...
Dimension 0 (across) _ _ _ _ _ _ _ _ _ _ _ _ _ |_ 0 _|_ 0 _|_ 0 _|_ 2 _| Dimension 1 |_ 1 _|_ 0 _|_ 2 _|_ 0 _| (down) |_ 0 _|_ 3 _|_ 0 _|_ 6 _| |_ 0 _|_ 0 _|_ 0 _|_ 0 _| I "care about" dimension 0 only, and "don't care" about the rest (dim 1). Summing this array with the above specifications will "collapse" the "stacks" of dimension 1 down to a single 4 x 1 array: _ _ _ _ _ _ _ _ _ _ _ _ _ |_ 1 _|_ 3 _|_ 2 _|_ 8 _| This can then be summed, or have any operation performed.
これを「n」次元の配列で行う必要があります。これはおそらく 20 次元です。また、特定の次元を考慮し、残りの部分を折りたたんで、これを実行できる必要があります。20 次元を視覚化できないため、これには特に苦労しています :p 。誰かが折りたたみ/合計するための C/C++ コードのセットアップを手伝ってくれたら、とても感謝します。
アップデート:
家に着いたばかり。あなたの質問に答えるための情報を以下に示します。
- 編集をロールバックして申し訳ありません。ロールバックをクリックすると変更内容が表示され、ウィキペディアのように、何を間違えたのかがわかるようになるのではないかと期待していました。私が調べたところ、そうではありませんでした。
- @jeff - 何が意味不明ですか?私はこの素晴らしいサービスを正当な理由(と私が思う)で利用しています。高校生なので趣味だけでももっと上手くなりたいです。私の投稿の多くは、遺伝的アルゴリズムの実装に関するものです (この投稿、sparsearray、配列のランク付け、ポインター操作)。
- 従来の(密な)配列を使用すると宇宙の分子の数を超える可能性があるため、私は疎な配列表現を使用しています。現時点では、sparsearray の実装自体はあまり重要ではありません。スパース表現に移行する前に、標準配列で動作するように取り組んでいるからです。私の以前の質問を見ていない人のために説明すると、私はスパース配列ポイントを含む構造として二分探索ツリーを使用し、必要に応じてツリーを走査し、関数が行うように設計されたものを返す「ドライバー」関数を使用しています。これは柔軟なので、配列にアクセスするさまざまな方法に対応できます。
- 構造はハイパーキューブであり、次元の数と各次元の長さが実行時に指定されます (ハイパーキューブであるため、これらはすべて同じです)。
皆さんのご意見に感謝します。
解決
これには応用できるかもしれません。2D コンウェイのライフ ゲーム (2D 平面、1 が「生きている」、0 が「死んだ」を定義する) を実装し、反復ごとにゲーム履歴を保存したとします (これにより 3D 立方体が定義されます)。歴史上、生きていた細菌の数を知りたい場合は、上記のアルゴリズムを使用します。Game of Life グリッドの 3D (および 4D、5D など) バージョンにも同じアルゴリズムを使用できます。
これは再帰に関する質問だったと思います。私はまだ C プログラマではありませんが、C でそれが可能であることは知っています。Pythonでは、
def iter_arr(array):
sum = 0
for i in array:
if type(i) == type(list()):
sum = sum + iter_arr(i)
else:
sum = sum + i
return sum
- 配列内の各要素を反復処理する
- 要素が別の配列の場合は、関数を再度呼び出します
- 要素が配列でない場合は、それを合計に加算します
- リターン合計
次に、これを「関心のある」ディメンションの各要素に適用します。
Python ではダックタイピングがあるため、これは簡単ですが...
他のヒント
@ジェフ
実際、これは興味深い質問だと思います。それがどれほど役立つかはわかりませんが、それは正当な質問です。
@エド
この質問についてもう少し詳しく教えていただけますか?配列の次元は動的であると言いましたが、要素の数も動的ですか?
編集:とにかく質問に答えてみます。頭の中でコードを説明することはできません (この PC にコンパイラーがないとコードを正しく理解するには時間がかかります)、正しい方向へ導くことはできます...
例として、インデックス 0 ~ 3 を持つ 8 次元 (0 ~ 7) を使用してみましょう。重要なのは 1、2、6 だけです。これは、2 つの配列があることを意味します。初め、 array_care[4][4][4]
1、2、6の場合。の array_care[4][4][4]
最終結果を保持します。
次に、非常に具体的な方法で繰り返していきたいと思います。配列があります input[4][4][4][4][4][4][4][4]
解析するには、次元 1、2、および 6 を考慮します。
いくつかの一時インデックスを定義する必要があります。
int dim[8] = {0,0,0,0,0,0,0,0};
インデックスを増やす順序も保存する必要があります。
int increase_index_order[8] = {7,5,4,3,0,6,2,1};
int i = 0;
この順序は、要求されたことを実行するために重要です。
終了フラグを定義します。
bool terminate=false;
これでループを作成できます。
while (terminate)
{
array_care[dim[1]][dim[2]][dim[6]] += input[dim[0]][dim[1]][dim[2]][dim[3]][dim[4]][dim[5]][dim[6]][dim[7]];
while ((dim[increase_index_order[i]] = 3) && (i < 8))
{
dim[increase_index_order[i]]=0;
i++;
}
if (i < 8) {
dim[increase_index_order[i]]++; i=0;
} else {
terminate=true;
}
}
これは 3 次元を考慮して、8 次元で機能するはずです。ダイナミックにするにはもう少し時間がかかりますが、時間がありません。お役に立てれば。申し訳ありませんが、コードのマークアップをまだ学習していません。:(
STL コンテナを使用すると、この種の作業ははるかに簡単になります。 Boost.MultiArray. 。ただし、配列を使用する必要がある場合は、次のようにします。
#include <iostream>
#include <boost/foreach.hpp>
#include <vector>
int sum(int x) {
return x;
}
template <class T, unsigned N>
int sum(const T (&x)[N]) {
int r = 0;
for(int i = 0; i < N; ++i) {
r += sum(x[i]);
}
return r;
}
template <class T, unsigned N>
std::vector<int> reduce(const T (&x)[N]) {
std::vector<int> result;
for(int i = 0; i < N; ++i) {
result.push_back(sum(x[i]));
}
return result;
}
int main() {
int x[][2][2] = {
{ { 1, 2 }, { 3, 4 } },
{ { 5, 6 }, { 7, 8 } }
};
BOOST_FOREACH(int v, reduce(x)) {
std::cout<<v<<"\n";
}
}
実際には、列を折りたたむことですでに列を合計しているため、この例では次元はまったく重要ではありません。私が何かを見逃したのか、それともあなたが見逃したのか?
ここで行う最善のことは、次の 2 つのことのうちの 1 つまたは両方であると思います。
- 設計が複雑すぎる場合は、設計を再考し、より複雑でない方法を見つけてください。
- 視覚化するのはやめてください。:P 合計する必要がある問題のディメンションを保存し、一度に 1 つずつ実行してください。基本コードを取得したら、アルゴリズムの効率の向上を検討します。
違うことを懇願しますが、常に別の方法があります。
そして、もしあなたが本当に できない リファクタリングを行う場合は、問題をより小さな部分に分割する必要があります。先ほども言ったように、合計する必要がある次元を確立してから、一度に 1 つずつ入力してください。
また、編集内容を変更するのはやめてください。彼らはあなたのスペルミスを修正しており、あなたを助けようとしているのです ;)
これをC/C++でやっているのですね...つまり、配列の配列の配列があります...2 次元の場合、メモリ内でのデータの配置方法は異なりますので、20 次元を視覚化する必要はありません。
[1] --> [1,2,3,4,5,6,...]
[2] --> [1,2,3,4,5,6,...]
[3] --> [1,2,3,4,5,6,...]
[4] --> [1,2,3,4,5,6,...]
[5] --> [1,2,3,4,5,6,...]
. .
. .
. .
では、なぜ最初の内容を合計する処理を繰り返すことができないのでしょうか?サイズを調べたい場合は、 sizeof(array)/sizeof(int)
危険なアプローチです。このデータを処理できるようにするためのディメンションを理解し、合計する再帰の深さを知るためにメモリを設定する必要があります。ここにあなたがすべきことを示す疑似コードがいくつかあります。
sum( n_matrix, depth )
running_total = 0
if depth = 0 then
foreach element in the array
running_total += elm
else
foreach element in the array
running_total += sum( elm , depth-1 )
return running_total
x = number_of_dimensions;
while (x > 1)
{
switch (x)
{
case 20:
reduce20DimensionArray();
x--;
break;
case 19:
.....
}
}
(ごめんなさい、我慢できませんでした。)
私の理解が正しければ、1 次元に沿って各「ビン」で定義された断面内のすべての値を合計したいことになります。宛先の 1D 配列を作成し、配列内の各要素をループして、対象の次元のインデックスを使用して宛先に値を追加することをお勧めします。
任意の数の次元を使用している場合は、要素をアドレス指定する方法が必要です (これをどのように実装しているか知りたいです)。これの実装は、宛先インデックスの設定方法に影響します。ただし、明らかな方法は、反復ループ内で if ステートメントをチェックすることです。
次元がいくつあるかわからないと言う場合、データ構造をどのように正確に定義しているのでしょうか?
ある時点で、誰かがこの配列を作成する必要があります。そのためには、配列の次元を知る必要があります。作成者にこのデータを配列とともに渡すように強制できます。
そのようなデータ構造を定義することが問題でない限り...