プロが教える店舗&オフィスのセキュリティ対策術

たびたびお世話になっております。

PERL 5.14.2 (Windows 7)を コマンドプロンプト上から動かしています。

use strict;
use warnings;

@multi_dimension_arrays; # $multi_dimension_array[$x][$y][$z]

というような配列の中身を最初に0初期化したいのですが
$x, $y, $zがどれだけ増えるかわかりません。

(0初期化していないので、大小比較などでエラーとなることがあります)

0初期化の方法をお教えください。

A 回答 (7件)

配列 @a に対し $#a で「@a の最後の添字」が得られるというのはよく知られているところですが, $#a を左辺値として使うと「@a の最後の添字を決める」ことができます. 例えば


$#a = 6;
とすると, @a の大きさは (添字にして 0~6 の) 7 となります. 配列が大きくなる場合は undef で埋め, 小さくなるときには余計なところがだまって消滅します.

んで #4 の「美しくない」ってのは, map を単に「ならべる」ために使うのがうれしくないなぁ, と.
@a = ([([(0) x ($z+1)]) x ($y+1)]) x ($x+1);
とできればいいんだけど, 実は間違っている.

以下は #6 向け (笑)
perl 5.14 の場合, 代入する値が定数なら 0 でも 100 でも同じコードを吐きます. まぁ, 0 であったところで何かが簡単になるわけじゃないので, わざわざ変える必要もないでしょう. そして, 機械語の場合でも「引き算」と「排他的論理和」と「単に 0 を代入」とで, 微妙に動作が違うことがあったりする. 例えば 8080 とか Z80 とかだとフラグの変化が全て違うので, 変なことをすると「0 を代入」じゃないと動かないことがある (この辺は 8086 でも同じだったはず). 一方 68000 では「0 を代入」で十分なので, 排他的論理和を使う必要はありません (使ってもいいけど何もかわらない).
    • good
    • 0
この回答へのお礼

$#a を左辺値として使うと「@a の最後の添字がきめれるというのは知りませんでした。
ありがとうございました。

お礼日時:2012/11/22 17:48

ANo.4さんのリストはなかなかすっきりしてきれいでしたので参考にさせてもらって後学の為実際に動作確認してみました。



my @a = map{[map{[(0)x($z+1)]}0..$y]}0..$x;

こんな感じで動きましたがどうでしょうか。

なかなか興味深い質問で、特定範囲の配列を定義するには範囲最大の配列に値を入れればいいなどという技とか、昔のバージョンでは動かない論理演算子「//」など学習できました。

ちなみに変数一個だけの0クリアは古典的な手法で、ネイティブなコンパイラでないperlは内部的にどうなるのかわかりませんが、排他的論理和をとるのが一番効率がいいです。
これは、機械語にしたときかなり小さいステップの命令数(アキュームレータ対象なら1命令)ですむというアセンブラ職人の技みたいなものです。
perlではこんな感じ

$a ^= $a;

Cなんかでも最適化オプションでコンパイルすると「A=0;」でも「mov A,0」とならずに「xor A」とかになっちゃいます。
実際、perl内部処理ではどうなるのか興味は尽きないところです。

化石の戯言ですのでスルーでお願いします。
    • good
    • 0
この回答へのお礼

かなりむずかしくなってきましたが
ありがとうございました。

お礼日時:2012/11/22 17:46

$a += $b;


は本質的に
$a = $a + $b;
と同じなんだから,
$a //= $b;
は本質的に
$a = $a // $b;
と同じ.

なお, #4 は $x, $y, $z の順序を間違えてます.

参考URL:http://perldoc.perl.org/perlop.html#Logical-Defi …
    • good
    • 0
この回答へのお礼

//
は知りませんでした。
ひいてみます。

ありがとうございました。

お礼日時:2012/11/22 17:44

@a = map { [ map { [ (0) x $x ] } 1 .. $y ] } 1 .. $z;



う~ん, 美しくない....
    • good
    • 0
この回答へのお礼

ありがとうございます。
ただ、私のあたまがついていきません。。。

ちなみに
if ( ($var //=0) == 3){
とやると初期化してない$varに0が入るみたいですね。

//=0 てどういう意味でしょう? +=0とのちがいは?

お礼日時:2012/11/20 19:56

>Cとかだと 定義するときに = 0 とか書けますよね。


Perlも書けます。
単に定義しないで突発的にない物を使うから書くタイミングがないだけだと思うのですが。


解決策はいくつかあります。
1: definedが未定義値かそうでないかを判別させます。
2: /^0$/ と正規表現を使用。文字列として0がひっかかるかどうか。($x eq 0 より速い)。
3: 変数内が必ず数値の場合、もう面倒なら偽なら全部0を代入する。 $x or $x = 0;

以上までが判定させる場合の処理。
その都度やらなくても、タイミング的に適切な場所で、
未定義値を0に変換する関数(もちろん配列変数を操作する関数)に飛ばすのが多くの場合よいと思う。
不可能ならその都度個別におこなう。


1: @y = (0) x $x; # $x 個の 0 で構成されたリスト値を返す。
(Perl特有の突発的な変数の発生に対応出来ないので使いにくい)。

以上は判定はさせないが先に決めておく方法。


上記のどちらも余計な行数(処理)が加わります。
ほとんどの場合、どちらも書かずに処理を作ることができます。
ただし、それはデータ構造の作り方と使い方に起因するのでここで例は示せません。


#----------------------------------

直接関係ないけど。

$array[$x][$y][$z];
は動的に定義されてるんだろうと思いますが、
定義した瞬間代入せんのですか?

それとも $x や $y の数字は飛び飛びなんですか? (0, 4, 9) みたいな。
それで$xが1だったりした時に未定義値になるんですか?
だとしたら構造に問題があると思います。

もし違うなら、存在しないものにアクセスして内部で自動生成させる時は、
なるべくその場で代入する時だけにするのがいいです。

あるのかないのか分からない物にアクセスしておいて、
あると決め付けてその場で使うのは違うと思うです。


たまにどうしてもそうゆう処理で作りたい時もありますが、
最低でも「あると決め付け」をせず、「あるのかないのか分からない」と言う前提の記述が必要です。
    • good
    • 0
この回答へのお礼

たいへん丁寧なご回答ありがとうございます。

配列の添え字、$x, $y, $zはとびとびではないですが、ふえていきます。

沿え字の上限はだいたいわかっているので
その分 0初期化してしまってもよいですね。

Cだと 構造体の定義文で = 0と書いておけばよかったように思いますが
Perl だと
@y = (0) x $x; # $x 個の 0 で構成されたリスト値を返す。
というのがあるのですね。ただ 多次元だとどうでしょう。
for ($x = 0; $x < 1000; $x++ ){
for ($y = 0; $y < 1000; $y++ ){
   for ($z = 0; $z < 1000; $z++ ){
ということでしょうか。

お礼日時:2012/11/20 12:02

実のところ「大小比較などでエラーとなることがあります」の「エラー」がどんなものか見えてないんだけど, ひょっとして autovivify がらみかな?



もしそうなら //= が最も安全な気がします. 例えば
if ($multi_dimension_array[$x][$y][$z] == 3) { # 以下省略
では autovivify できずにエラーが出たかもしれない. それ系のエラーなら
if (($multi_dimension_array[$x][$y][$z] //= 0) == 3) { # 以下省略
でごまかせる... けど面倒だなぁ. たぶんどうにもならんと思うけど.
    • good
    • 0
この回答へのお礼

エラーは uninitilized ....とかいうメッセージでした。
さきほどの方の助言どおり 0を足してやってますが、

//= 0) == 3) も試してみます。

ありがとうございました。

お礼日時:2012/11/20 11:50

「初期化してなければ undef」だから, 大小比較すると 0 とみなされるはずなんだけど....



必要なら 0 を足せばいいんじゃないかなぁ. あるいは // 使うとか.
    • good
    • 0
この回答へのお礼

そうですか。。
Cとかだと 定義するときに = 0 とか書けますよね。。

でも、Cだと要素数を決めておかないといけませんから
一長一短というところでしょうか。

ありがとうございました。

お礼日時:2012/11/19 09:13

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!