2011-12-02 9 views
4

申し訳ありませんが、これは私が(動的)配列はDで本当に強力ですが、以下は、しばらくの間、私を悩ませてきたと思うのアレイにD動的配列の初期化、ストライドとインデックス操作

についての3倍の質問になりました:

私は簡単に指定された値で配列を割り当てることができましたが、DIではそうする方法が見つかりませんでした。

int[] a = new int[N]; 
a[] = a0; 

しかし、それはa0と1が0で初期化されますので、ライン、非効率的に見える、など2:確かに次は問題ありません。次のような何かがDで行われるでしょうか?

int[] a = new int(a0)[N]; // illegal 

std.rangeにストライドを使用するときに私が持っているもう一つの効率事項:

import std.stdio; 
import std.range; 

struct S 
{ 
    int x; 

    this(this) 
    { 
     writeln("copy ", x); 
    } 
} 

void f(S[] s) 
{ 
} 

int main() 
{ 
    S[] s = new S[10]; 
    foreach (i, ref v; s) 
    { 
     v.x = i; 
    } 

    f(stride(s, 3)); // error 
    return 0; 
} 

は確かに私は、私は単にそれの要素をコピーせずに新しい配列を作成するためにストライドを使用することができナイーブ考えていましたか? Dでそうする方法はありませんか?代わりに、(X)を取得書く方法があるでしょう

f(s, 3); 

void f(S[] s, uint stride) 
{ 
    ref S get(uint i) 
    { 
     assert (i * stride < s.length); 
     return s[i * stride]; 
    } 

    for (uint x ...) 
    { 
     get(x) = ...; 
    } 
} 

インデックス演算子を使用した:配列がストライドが戻ってくるようだった、ととしてfを実装しているかのよう


は、だから私は行ってシミュレートget[x]?このようにして、strideのget関数を静的にmixin/includeし、残りの関数を同様に保つことができました。ローカルの構造体が関数のスコープ変数にアクセスすることは許可されていないので、私は取り組んでいるアプローチに興味があります(どうしてですか?)。

答えて

7

しかし、1行目が0で初期化され、2とa0のように非効率的に見えます。次のような何かがDで行われるでしょうか?

使用std.array.uninitializedArray

S[] s = uninitializedArray!(S[])(N); 
s[] = a0; 

は確かに私は、私は単にそれの要素をコピーせずに新しい配列を作成するためにストライドを使用することができナイーブ考えていましたか? Dでそうする方法はありませんか?

あなたの機能fは何strideリターンとは異なり、引数としてS[]を持っています。これを解決するためのDの方法は、あなたのf関数がテンプレートすることによって任意の範囲を受け入れるようにすることです:

void f(Range)(Range s) 
{ 
    foreach (item; s) 
     // use item 
} 

S[] s = new S[10]; 
f(s); // works 
f(stride(s, 3)); // works too 

別の方法としては、配列にコピーすることができます:

f(array(stride(s, 3))); 

をしかし、あなたはおそらくコピーを避けたいです大きい場合は配列全体。


ではなく、インデックス演算子[x]はgetを使用して(x)を取得書くための方法はありますか?こうすることで、striding get関数を静的にmixin/includeし、残りの関数を同様に保つことができます。ローカルの構造体が関数のスコープ変数にアクセスすることは許可されていないので、私は取り組んでいるアプローチに興味があります(どうしてですか?)。

独自の構造体でインデックス演算子をオーバーロードすることができます。

これは、実際のstride機能の(種類の)方法です。私はRangesを読むことをお勧めします。

+0

読んでいただきありがとうございます。特定の構成ではパフォーマンスがわずかに低下するかもしれませんが(おそらく私はそれらを悪用します)、コードはよりクリーンで包括的です。なぜopIndexとopIndexAssignの違いは、単にopcodeを返すことができないのですか? –

+0

パフォーマンスの問題が解決しました。 C libの配列をポインタからRangeに変換した後、コードはより洗練されたものになった。速度の違いは気づかれませんでした。 –

+0

'void f(Range)(...)'を制約する必要があります。 'isInputRange'? –

1

あなたは(のコピーを作成する).dupを持つ配列を複製することができます(これもスライスで動作します)か、配列初期化子

int[] a=a0.dup; 
int[] b=[e1,e2,e3]; 

で要素を設定することができますが、(F一般的なことができますストライドは()あなたが反復処理することができ、構造体、配列ではない)

void f(Z)(Z s)if(isInputRange!Z){ 
    foreach(elem;s){ 
     //... 
    } 
} 

配列は、いくつかのメモリブロックへのポインタフィールドとサイズフィールドを持つ本質的構造体であることを覚えておいてくださいを返し

+0

a0が値の場合、dupメンバーは存在しません。そして、 'int [] b = [a0、a0、a0、a0 ...(N times)];は厳しい作業です。したがって、要素のデフォルトのコンストラクタ以外のものを使用して配列を割り当てる方法はありません(たとえば、intを値で設定し、構造体については同じものを0に設定するなど)。 –