親のIDのあるデータをツリー状に並べたい

このQ&Aのポイント
  • データを親のIDを基にツリー状に並べたい場合、配列を利用して処理することができます。
  • ツリーを作成するために、データを適切な形式に整理する必要があります。
  • 特定のデータに対して、親データを特定する方法を使用することで、ツリー構造を作成できます。
回答を見る
  • ベストアンサー

親のIDのあるデータをツリー状に並べたい

@data=( '1<><>あああああ', '2<><>いいいいい', '3<>1<>ううううう', '4<>3<>えええええ', '5<>2<>おおおおお', ); このような <>で区切ったデータがあるとします。 一番左の数字は、そのデータのIDで、その次の数字は、 その親データのIDです。 このデータを、 1<><>あああああ  3<>1<>ううううう   4<>3<>えええええ 2<><>いいいいい  5<>2<>おおおおお のようなツリー形式に並べたいのです。 []を1つのノードと考えた $nodes=['1<><>あああああ',['3<>1<>ううううう',['4<>3<>えええええ']],'2<><>いいいいい',['5<>2<>おおおおお']]; のような配列を作れれば、 $nodes=['1<><>あああああ',['3<>1<>ううううう',['4<>3<>えええええ']],'2<><>いいいいい',['5<>2<>おおおおお']]; sub tree{ my($i); my $depth = shift; my $ref = shift; foreach(@{$ref}) { if (ref($_) eq "ARRAY") { &tree($depth+1, $_); } else { for($i=0;$i<$depth;$i++){ print " "; } print $_."\n"; } } } &tree(0,$nodes); というコードでツリーにできるところまではできました。 ですが、 @dataから$nodesを作る方法がわからず困っています。 $nodesは多少違うものでも構いませんので、 何かいい方法があれば教えてください。 よろしくお願いします。

  • Perl
  • 回答数1
  • ありがとう数1

質問者が選んだベストアンサー

  • ベストアンサー
回答No.1

いい方法というか、普通に親子関係を配列に入れていおいてたどればよいと思いますが... 最初のforeachで親子関係を格納した配列を作って、ハッシュから値も引けるようにしておきます。 あとは再帰的に親子関係をたどりながら結果を格納していきます。 sub convert_data { my $d = shift; my @data = @$d; my @root = (); my @child = (); my %map = (); foreach my $elm (@data) { my ($id, $parent, $content) = split(/<>/, $elm); $map[$id] = $elm; if ($parent eq '') { push(@root, $id); next; } if (!defined($child[$parent])) { my @dummy = (); $child[$parent] = \@dummy; } $ref = $child[$parent]; push(@$ref, $id); } sub push_child { my $ref = shift; my @ret = (); foreach my $id (@$ref) { push(@ret, $map[$id]); if (defined($child[$id])) { push(@ret, &push_child($child[$id])); } } return \@ret; } return &push_child(\@root); } my $nodes = &convert_data(\@data); 最近Perlを書いていないのでデータ構造はあまりエレガントではないですが。

neko173
質問者

お礼

出来ました。 ありがとうございました。 とても助かりました。

関連するQ&A

  • ツリービューの使い方が・・・

    VBのカスタムコントロールはほとんどさわったことがないので、ぜんぜんわからないです。 初心者っぽい質問で申し訳ないのですが、プロセスとプロセスがもっているスレッドを、プロセスID&スレッドIDをキーにツリー構造を持たせたいのですが、ツリービューのツリーへのアクセスのしかたがわかりません。 MSDNライブラリが壊れているようで、ヘルプが出ないのです。 新しいMSDNライブラリ入れてから、トラブル続き。 TreeView1.Nodes.Add , , "キー", "値" TreeView1.Nodes.Add , , "キー\サブキー", "値" じゃなさそうみたいです。 かといってそれぞれのノードが小枝への参照をもっているわけでもないし、小枝を追加するメソッドをもっているわけでもないし。 単純に小枝への追加のしかたが知りたいだけなんですけど・・・。 だれか教えてください。

  • @data[0] = "id,http://okweb.com/WE7

    @data[0] = "id,http://okweb.com/WE7@x,pass"; @data[1] 以降続く。 foreach (@data) { ($id,$url,$pass)=split(/\,/,$_); if ($id eq $in{'id'}) {last;} } print "$url\n"; これだと $url の@以降の部分が表示されずに http://okweb.com/WE7 このようになってしまいます。 @data = "id,http://okweb.com/WE7\@x,pass"; このように、@の前に\を入れれば大丈夫なのですが、他に何かよい方法はないでしょうか?

    • ベストアンサー
    • Perl
  • VB2005 ツリービューに子ノードを追加

    VB2005 ExpressEditionにて開発しています。 フォームロード時にデータセットからツリービューにデータをセット しようとしています。 ルートノードには  Dim Node As TreeNode  Node = TreeView2.SelectedNode  TreeView2.Nodes.Add("追加したい名前") で追加できます。 子ノードを追加する時はどうしたらいいのでしょうか。 ご存知の方がいらっしゃいましたら教えて下さい。 よろしくお願いします。

  • Perl/配列のループに関して教えてください。

    my @shop = [ {'start_hour'=> '1100','shift'=> [1,2] }, {'start_hour'=> '1130','shift'=> [1,3] } ] という配列があってそれをループで回したいのですが、 ▼以下だとNG foreach my $data (@shop){print $data->{start_hour};} ▼以下だと最初の1つだけOK foreach my $data (@shop){print $data->[0]->{start_hour};} という状況です。なぜ$data->{start_hour};で取得できないのでしょうか? 助けて頂けるとうれしいです★

    • ベストアンサー
    • Perl
  • C++言語のプログラムをfortranに変換

    foreach node in nodes: node.done = false node.cost = -1 nodes[start] = 0 // スタートノードのコストは0 // アルゴリズム実行 loop: // 確定ノードを探す doneNode = null // 確定ノード foreach node in nodes: if node.done or node.cost < 0: continue if doneNode == null or node.cost < doneNode.cost: doneNode = node // 確定ノードがなくなれば終了 if doneNode == null: break // 確定フラグを立てる doneNode.done = true // 接続先ノードの情報を更新する for i = [0, doneNode.edges_to.size()-1]: to = doneNode.edges_to[i] cost = doneNode.cost + doneNode.edges_cost[i] if nodes[to].cost < 0 or cost < nodes[to].cost: nodes[to].cost = cost このプログラムをfortranに変換できる方いますか? できる方、よろしくお願いいたします。

  • XML::Simpleの使い方について

    下記のような、プログラムを書いたのですが、上のタイトルはとれるのですが、連続して出てくるentryがどうしても取得できません。 何かご助言頂ければありがたいです。 my $url = "http://blog.livedoor.jp/takapon_ceo/atom.xml"; my $xml = get($url); my $tree = XMLin($xml); my $title = $tree->{title}; print "$title"; for (my $i = 0; $i <= 5; $i++) { $id[$i] = $tree->{'entry'}->[$i]->{'id'}; print "$id[$i]"; } よろしくお願いします。

    • ベストアンサー
    • Perl
  • サブルーチンの結果

    my @data; my ($rows,$cols); sub Gettest { use Text::ParseWords; my $dfile = shift; # CSVファイル my @array = @_; @data = (); open(IN, $dfile) or exit(-1);# while(<IN>) { chomp; my @fields = quotewords("," => 0 , $_); # カンマデータの取込 foreach my $field (@fields){ if(index($field, ":") >= 0) { my @range = split(':',$field);# 範囲の取出し $field = sub { my $v = shift; return $range[0] <= $v && $v <= $range[1];}; } elsif(index($field, ",") >= 0) { my @list = split(',',$field); #種類の取出し $field = sub { my $v = shift; return grep($v == $_, @list); };}} push @data, [@fields];} close(IN); $rows = @data; $cols = @{$data[0]}; return squeezed(@array);#// 該当範囲の絞り込み} sub squeezed { my @para = @_; my @pos = (0 .. ($cols -1)); my $i; my @wk; for($i = 0; $i < $rows -1; $i++) { @wk = (); foreach my $p (@pos) {# 有効な位置 my $test = $data[$i]->[$p]; if("CODE" eq ref($test)){ # 範囲テストコードの場合 push @wk, $p if &$test($para[$i]); # test がOK } elsif($para[$i] eq /$test/) {push @wk, $p; # マッチ位置を配列に}} @pos = @wk;} if(@pos == 1){ return $data[-1]->[$pos[0]]; } else {return undef;#// 該当なしか2個以上ならundefを返却 }}1; 引数によってCSVデータの範囲を絞って結果を返すといった関数を、ご提供して頂いた のですが、「1:4」や「1,3,4」等の答えがCODE(XXX)になってしまいます。ご提供者様から、ループで変換するのではなく 最終行のみ変更を加えないようにするというアドバイスを頂いて色々ためしてみたのですが、 私のレベルではサブルーチンの理解が出来なくて全然うまくいきません。他力本願な お願いで申し訳ないのですが、解る方教えて下さい。

    • ベストアンサー
    • Perl
  • perl ファイルのデータを編集したい

    初めまして、perl をやり初めたばかりです。作業は Linux 上で行ってます。 あるテキストファイル data.txt があります。 data.txt の中は、以下のようになっているとします。 100 200 300 400 500 600 これを読み込んで、例えば、 1 2 3 4 5 6 以上の様に各数字を百分の一にして出力したいと思ってます。 一応、色々と調べながらプログラムを書いてはみましたが 思う様に出力されません。以下そのプログラム。 #!/usr/bin/perl open(IN, "data.txt") or die ; @x = <IN>; close (IN); $ref_x = \@x; $n_data = @x; for ($i = 0; $i< $n_data; ++$i) { $$ref_x[$i] /= 100 ; print $x[$i], " "; } print"\n"; どなたか、perl にお詳しい方教えていただけないでしょうか? 宜しくお願い申し上げます。

  • 参照配列の要素数の求め方は?

    リファレンス配列の要素数は、$#では求められないのでしょうか? ------------------------------------- foreach $i(0 .. 3){ $hash->[$i] = $i * 100; } print "\%hashの要素数->$#hash\n"; $ref = \%hash; print "\%{$ref}の要素数->$#{$ref}\n"; -------------------------------------

    • ベストアンサー
    • Perl
  • データを書き換えたいのですが・・・

    以下の方法で、CGIを書いたのですが、ユーザーIDを入れても、データベースを書き換えられません。 どこが問題なのか、教えて頂きたく質問しました。 *何分初心者で、見づらいと思いますが、宜しく御願いします。 ★目的  ユーザIDを入れると、”hanteinasi”の人が”hanteiari”にデータベースに書き換えられる。 ★データベース ○ユーザID:名前:メール:性別:年齢:(判定ありorなし):認証ID: 例)kk432 : 佐藤 : j@co.jp : 男 : 20 : hanteinasi : q1234 : ★CGI #!/usr/local/bin/perl require 'cgi-lib.pl'; &ReadParse(*form); require 'jcode.pl'; &jcode'convert(*form, 'sjis'); open(ENQ,"+<enquete.dat") || die "File 'enquete.dat' Open Error."; @add= <ENQ>; $i=0; chop @add;; foreach (@add){ ($userID, $name, $mail, $sex, $age, $hantei, $ninsyouID )=split(/:/, $_); if( $form{'user'} eq $userID && $hantei eq "hanteinasi"){ $hantei= "hanteiari"; @add[$i]; = "$userID:$name:$mail:$sex:$age:$hantei:$ninsyouID:\n"; i++; flock(ENQ, 2); print ENQ @add[$i]; flock(ENQ, 8); } elsif($hantei eq "singuru" || $hantei eq "hanteinasi"){ @add[$i] = "$userID:$name:$mail:$sex:$age:$hantei:ninsyouID:\n"; i++; flock(ENQ, 2); print ENQ @add[$i]; flock(ENQ, 8);}} close(ENQ); # -----ここから出力 ----- print "Content-type:text/html\n\n"; print << "END_OF_HTML"; <HTML><HEAD><TITLE>登録完了</TITLE></HEAD> <BODY><CENTER><FONT color="red"> 登録完了 </FONT></CENTER></BODY></HTML> END_OF_HTML}EOF

    • ベストアンサー
    • CGI

専門家に質問してみよう