10

単純な言語用のJavaScriptインタープリターを構築する過程で、私は次の問題に直面しました。

解析後、変更するn次元配列の要素を指定するインデックスの配列を取得します。たとえば、これを解析した後:

a[1, 1, 1]

配列を取得し[1, 1, 1]ます。私が取り組んでいる言語には変数定義がないため、変数は最初の使用時に初期化されます。私の目標は、このn次元配列を作成して、変数テーブルに配置できるようにすることです(上記の例では、3次元配列を作成する必要があります)。

短い質問:

を使用せずにJavaScriptでn次元配列を作成する方法はありますeval()か?

4

9 に答える 9

12

Chromeでテスト済み:

function createNDimArray(dimensions) {
    if (dimensions.length > 0) {
        var dim = dimensions[0];
        var rest = dimensions.slice(1);
        var newArray = new Array();
        for (var i = 0; i < dim; i++) {
            newArray[i] = createNDimArray(rest);
        }
        return newArray;
     } else {
        return undefined;
     }
 }

次にcreateNDimArray([3, 2, 5])、3x2x5配列を返します。

同様の再帰的手順を使用して、インデックスが配列内にある要素にアクセスできます。

function getElement(array, indices) {
    if (indices.length == 0) {
        return array;
    } else {
        return getElement(array[indices[0]], indices.slice(1));
    }
 }

要素の設定も同様で、読者の練習問題として残しておきます。 

于 2012-09-25T18:18:37.483 に答える
5

何も組み込まれていませんが、その仕事をする関数を作成するのは非常に簡単です。

var genArray = function () {
    var arr, len, i;
    if(arguments.length > 0) {
        len = [].slice.call(arguments, 0, 1)[0];
        arr = new Array(len);
        for(i = 0; i < len; i++) {
            arr[i] = genArray.apply(null, [].slice.call(arguments, 1));
        }
    } else {
        return null; //or whatever you want to initialize values to.
    }
    return arr;
};

var a = genArray(3, 2); //is [[null, null],[null, null],[null, null]]
var b = genArray(3, 1, 1); //is [[[null]],[[null]],[[null]]]

a[0][1]; //is null
b[1][0][0]; //is null
b[1][0][0] = 3;
b[1][0][0]; //is 3;
b; //is [[[null]],[[3]],[[null]]]

多分それは助けになりますか?

PS-

これは必要以上の努力のように思えるかもしれません。ただし、残念ながら、JavaScript配列は実際には「配列」ではありません(「配列」とは、連続したインデックス付きの不変のメモリブロックを意味します)。それらはほとんどの言語の「地図」のようなものです。したがって、それらの作成にはある程度の努力が必要です。ほとんどの言語は、単純な乗算とそれに続く。を実行しているだけなので、多次元配列の作成に問題はありませんmalloc()。ただし、JavaScriptを使用する場合、配列を事前に構築する場合は、配列を再帰的に生成する必要があります。それは苦痛ですが、通訳が必要とする努力を示しています。

図に行きます。

于 2012-09-25T18:15:36.610 に答える
1

n次元配列を作成するには:

function createNDimArray(dimensions) {
 var ret = undefined;
 if(dimensions.length==1){
    ret = new Array(dimensions[0]);
    for (var i = 0; i < dimensions[0]; i++)
        ret[i]=null; //or another value
    return ret;     
 }
 else{
    //recursion
    var rest = dimensions.slice(1);
    ret = new Array(dimensions[0]);
    for (var i = 0; i < dimensions[0]; i++)
        ret[i]=createNDimArray(rest);       
    return ret;
 }
}
于 2013-05-03T11:32:22.663 に答える
1

編集:再帰的なソリューションでは、作成できる配列のサイズに制限があるため、 PJ@GitHubライブラリで別のソリューションを作成しました。これは疑似インスタント速度で実行され、任意のサイズ、任意の構造、任意のブランチの任意の次元の多次元配列を作成および管理できます。また、事前入力をシミュレートしたり、カスタムデザインのノードオブジェクトを使用したりすることもできます。ここでそれをチェックしてください:https://github.com/PimpTrizkit/PJs/wiki/14.-Complex-Multireflection-Object--(pCMO.js)


jfabrizioのソリューションの修正バージョンを使用する:

function createNDimArray(dimensions) {
    var t, i = 0, s = dimensions[0], arr = new Array(s);
    if ( dimensions.length < 3 ) for ( t = dimensions[1] ; i < s ; ) arr[i++] = new Array(t);
    else for ( t = dimensions.slice(1) ; i < s ; ) arr[i++] = createNDimArray(t);
    return arr;
}

使用法:

var arr = createNDimArray([3, 2, 3]); 
//  arr = [[[,,],[,,]],[[,,],[,,]],[[,,],[,,]]]
console.log(arr[2][1]); // in FF: Array [ <3 empty slots> ]
console.log("Falsy = " + (arr[2][1][0]?true:false) ); // Falsy = false

これはかなり速いことがわかりました。JavascriptでN次元配列を生成するのが可能な限り最速の方法であると言っても過言ではありません。上記のこのリファクタリングでは、速度がかなり向上しました。しかし、もちろん、最高の速度向上は事前充填を行わなかったことによるものです。このバージョンでは、アレイは事前に入力されていません。最後のレベルが単なる空の配列である、Nsの長さの完全に作成されたN次元配列のみを返します。arr[x][y][z]?arr[x][y][z]:nullあなたが本当に価値を必要とするならば、それで十分であることを願っていnullます。それは私の使用のためです。:)

事前入力が必要な場合は、彼の元のバージョンを使用してください。

そして、あなたが私がしたことを本当に気にしないのなら、その後、読書を停止します。

もっとオタクの話をしたいですか?そこから学んでいる人のための再帰について少し。さて、ここに戦術があります。深い再帰を行うときは、最終レベルを念頭に置いてください。ほとんどの作業が行われる場所です。この場合、文字通りN番目の次元です。これがあなたの「ペイロード」であり、残りはロジスティクスです。jfabの関数では、に到達dimensions.lengthする1と、最後の次元、N番目の次元に到達し、ペイロードを実行します。これは、nullの配列、または私の場合は空の配列を作成することです。再帰が非常に深くなるため、各次元は最後の次元の要因になります。N次元に到達するまでに、多くの関数呼び出しが発生し、コンピューターのロジスティクスが煩雑になります。そして、N番目の次元で、基本再帰関数を呼び出します(createNDimArray私たちの場合)ロジスティクスよりもペイロードの方が多くなります。さて、jfabの元のソリューションと同様に、ペイロードの実行を(可能であれば)再帰で最初に行うこととして配置することは、特に単純な場合は、通常は良いことです。ここでは、ペイロードを最終的な2D配列の構築にします(単に1D配列new Array()のみを返すのではなく)。そうすれば、このレベルで過剰な量の関数呼び出しを行う必要がなくなります。もちろん、配列を事前に入力する場合は、このショートカットが常に役立つとは限りません。しかし、もっと重要なことは、アレイを事前に入力することが適切なペイロードになるということです。しないでN次元のすべてのアイテムにアクセスすると、効果的に削除されました。そうすれば、関数呼び出しのレベルが1つ少なくなり、基本的にN番目の次元のペイロードは実際にはN-1番目の次元で実行されます。また、を配信するためだけに再帰関数を再度呼び出すことはありませんnew Array()。残念ながら、new Array(x)(一般的に)への呼び出しはそれをそのように見ていません。その実行時間は、が大きくなると長くなりxます。これは事実上、Nth Dimensionのすべてのアイテムにアクセスしていますが、今では1回だけ、ネイティブコードを使用して、タイトで軽いループにラップされています。ここで、これはcreateNDimArrayN> 1でのみ呼び出すことができる必要があります。つまり、1D配列の作成には使用されません。理論的には、より大きなNが必要になり、最後にさらに多くの次元を展開できます。基本的に、の行は次のif ( dimensions.length < 3 )ようになります< 4または< 5、そこにあるループの周りにさらに多くのループをラップするfor必要があり、それぞれに独自のvarsのセットが必要になります---過剰な機能を取引しているため、すべてがどれほど効率的かはわかりません同様のアイデアでスペース/操作を呼び出してスタックしますが、埋め込まれていますforループ---しかし、Nが常に特定のレベルを上回っていることがわかっている場合、または最終的な次元に対してのみである場合は、一部の環境を高速化できると思います。ここのように、私は最後の2つの次元でそれを行いました。しかし、展開しすぎると、ペイロード自体がクマになります。テストだけがそれが価値があるかどうかを教えてくれます。スタックスペースには限りがあるようですが、より多くの展開でより大きな配列を作成できたのを覚えていると思います。配列を作成できるサイズには制限があります。そして、N番目のレベルで各アイテムを呼び出す再帰ソリューションは、私がそうする場合、最低の制限がありました..思い出してください..正しく....はるかに低くなりました。

彼のソリューションを改訂する次の部分は単なるロジスティクスであり、過剰なブロックとコードを取り除くための単純なリファクタリングでした。すべてのvar作業に参加して、それだけです。arr戻る必要があるので、ループが終了すると、var最初にすべての作業を1行で実行することもできますが、幸いなことに、4つvarのうち3つは同じ初期化を行います。,可能であれば、Javascriptはと結合するときにコードを最適化できることを忘れないでください。これにより、コードも小さくなります。

PT

于 2015-09-24T10:55:10.030 に答える
0

、および関数をcreateNDimArray使用するもう1つのバージョン:mapapplybind

function createNDimArray(dims) {
    return dims.length === 1
        ? new Array(dims[0])
        : Array.apply(null, Array(dims[0])).map(createNDimensionalArray.bind(null, dims.slice(1)));
}
createNDimArray([3, 2, 5]); // returns 3x2x5 array
于 2015-12-20T11:28:56.450 に答える
0

NDアレイを作成するには、ネストされたNDアレイのクローンを作成する必要があります。したがって、適切な方法が必要にArray.prototype.clone()なり、残りは簡単です。私の知る限り、JSで最も簡単で効率的な方法は次のとおりです。

Array.prototype.clone = function(){
  return this.reduce((p,c,i) => (p[i] = Array.isArray(c) ? c.clone() : c, p),[])
}

function arrayND(...n){
  return n.reduceRight((p,c) => c = (new Array(c)).fill().map(e => Array.isArray(p) ? p.clone() : p ));
}

var NDarr = arrayND(4,4,4,4,"."); // size of each dimension and the init value at the end
console.log(JSON.stringify(NDarr))
NDarr[0][1][2][3] = "kitty"; //access any location and change.
console.log(JSON.stringify(NDarr))

于 2016-05-28T07:24:16.253 に答える
0

Anwserの理由

ここには良い答えがありますが、JavaScriptが変更されたため、JavaScriptの更新された機能のいくつかでこの問題に取り組むための追加の方法があります。

function nArray (dem, size=dem, fill=null, currDepth=0) {
    const arr = new Array(size).fill(fill);
    return (currDepth+1 === dem) ? arr : arr.map(i => nArray(dem, size, fill, currDepth+1));
};

ノート

dem配列の次元です。

sizeは各ディメンションのサイズです。デフォルトではdem値です。

fillデフォルトの入力値となる値です。

currDepth関数の再帰的な性質のために使用されるべきではありません。

于 2019-07-30T14:32:58.770 に答える
0

デフォルト値でn次元の行列配列を作成します

function arr (arg, def = 0){
      if (arg.length > 2){
        return Array(arg[0]).fill().map(()=>arr(arg.slice(1)));
      } else {
        return Array(arg[0]).fill().map(()=>Array(arg[1]).fill(def));
      }
    }

//simple usage -> fills with 0
var s = arr([3,5,8,4])  // 4 dimensions
var t = arr([5,7])  // 2 dimensions

//fill with null
var k = arr([4,7,9] , null)  // 3 dimensions 
于 2019-09-16T18:13:00.747 に答える
0

各クラスターでインデックスが0から4の4d配列を作成する必要がある場合は、次のコードを実行してください。

function createNDimArray(dimensions) {
    if (dimensions.length > 0) {
        var dim = dimensions[0];
        var rest = dimensions.slice(1);
        var newArray = new Array();
        for (var i = 0; i < dim; i++) {
            newArray[i] = createNDimArray(rest);
        }
        return newArray;
     } else {
        return undefined;
     }
 }
var MyArray=createNDimArray([5, 5, 5, 5]);
//returns a 5x5x5x5 array with index from 0 to 4;
MyArray[4][4][4][4]="MyArray 4d MyValue";
alert(MyArray[4][4][4][4]);



//For 5-demension array with this param.: 5x4x3x2x2 -> do this:
var MyArray_5d=createNDimArray([5, 4, 3, 2, 2]);
MyArray_5d[4][3][2][1][1]="MyArray 5d MyValue";
alert(MyArray_5d[4][3][2][1][1]);

于 2020-06-24T11:36:58.057 に答える