Tcl – 配列(4) -arrayコマンド(2)-

配列の要素を順番に参照するにはarrayコマンドの検索関連のオプションを使います。

この記事は配列の検索に関連するオプション(startsearch, nextelement, anymore, donesearch)の使い方と、配列を一旦リストに変換してからforeachコマンドを使って要素を順番に参照する方法を紹介します。

検索関連のオプション

[書式]

array startsearch arrayName

このコマンドは、arrayNameで指定された配列を要素単位で検索します。戻り値は、「array nextelementコマンド」及び「array donesearchコマンド」で使用する必要がある検索識別子(searchId)です。

array nextelementコマンドを呼び出すと、配列内の個々の要素名が返されます。検索が完了したら、array donesearchコマンドを呼び出す必要があります。同じ配列に対して複数の検索を同時に実行することができます。

[書式]

array nextelement arrayName searchId

配列arrayNameの次の要素名を返します。すべての要素が既に返されている場合は、空の文字列を返します。searchId(検索識別子)は、array startsearchコマンドの戻り値である必要があります。

[書式]

array anymore arrayName searchId

配列の検索において探索していない要素が残っているか調べます。未処理の要素が残っている場合は1を返します。すべて処理済みの場合は0を返します。

[書式]

array donesearch arrayName searchId

このコマンドは配列検索を終了し、その検索に関連するすべての状態を破棄します。

警告:要素が配列に追加されたり配列から削除されたりすると、array donesearchが呼び出されたかのように、すべての検索が自動的に終了します。これにより、これらの検索で配列のnextelement操作が失敗します。

検索関連のオプションは「array startsearch」と組み合わせて使用します。

[使用例1]

% array set progress {
    00:00 開始
    00:10 進捗1
    00:30 進捗2
    01:00 進捗3
    02:00 終了
}

% set sid [array startsearch progress]   ----(1)
s-1-progress

% array nextelement progress $sid        ----(2)
02:00
% array nextelement progress $sid
00:30
% array nextelement progress $sid
00:00
% array nextelement progress $sid
01:00
% array anymore progress $sid            ----(3)
1
% array nextelement progress $sid
00:10
% array nextelement progress $sid
% array anymore progress $sid            ----(3)
0
% array donesearch progress $sid         ----(4)

参考:progressは英語で「経過」という意味です。

<使い方>

  1. 「startsearch」で検索識別子(searchId)を所得する。
  2. 「nextelement」で要素名を取得していく。
  3. 「anymore」で探索していない要素が残っているか調べる。
  4. 「donesearch」で検索を終了します。

イマイチ使い方が良く分からないですよね。

さらに詳しく

[使用例2]

#!/bin/sh
# the next line restarts using tclsh \
exec tclsh "$0" "$@"

# 配列の作成
array set progress {
    00:00 開始
    00:10 進捗1
    00:30 進捗2
    01:00 進捗3
    02:00 終了
}

# 検索idの取得
set sid [array startsearch progress] 

# keyを順番に取得して要素を出力する。
while {[array anymore progress $sid]} {
    set key [array nextelement progress $sid]
    puts "progress($key) = $progress($key)"
}

# 検索の終了
array donesearch progress $sid

[実行結果]

progress(02:00) = 終了
progress(00:30) = 進捗2
progress(00:00) = 開始
progress(01:00) = 進捗3
progress(00:10) = 進捗1

使用例2を見てわかるように、検索オプションを使用することで、配列をリストに変換しなくても、要素の値を順番に参照することが出来ます。

配列(1)の記事の「要素名(key)に数字を使う」でも要素の値を順番に参照する方法を紹介しましたが、これは要素名(key)に整数値を使用して数値をカウントアップさせることで、要素を順番に参照するやり方でした。

検索オプションを使用すると、要素名が文字列でも要素名を順番に参照できます。

ところで、本家の「array startsearch arrayName」の説明を見ると以下の記載があります。

It is currently more efficient and easier to use either the array get or array names, together with foreach, to iterate over all but very large arrays.

訳すとこんな感じ

現在、「array get」または「array names」のとちらかをforeachと一緒に使用して、非常に大きな配列を除くすべての配列を反復処理する方が効率的で簡単です。

http://www.tcl.tk/man/tcl8.6/TclCmd/array.htm#M13

「非常に大きな配列」というのが、どの程度の要素数なのか分かりませんが、通常は、foreachコマンドで順番に取り出した方が、効率的で簡単なようです。

それでは、foreachコマンドを使用した方法を紹介します。以下の方法は、foreachコマンドを使用した方法です。

[使用例3]

#!/bin/sh
# the next line restarts using tclsh \
exec tclsh "$0" "$@"

# 配列の作成
array set progress {
    00:00 開始
    00:10 進捗1
    00:30 進捗2
    01:00 進捗3
    02:00 終了
}

foreach key [array names progress] {
    puts "progress($key) = $progress($key)"
}

puts "ソート"
foreach key [lsort -dictionary [array names progress]] {
    puts "progress($key) = $progress($key)"
}

[実行結果]

progress(02:00) = 終了
progress(00:30) = 進捗2
progress(00:00) = 開始
progress(01:00) = 進捗3
progress(00:10) = 進捗1
ソート
progress(00:00) = 開始
progress(00:10) = 進捗1
progress(00:30) = 進捗2
progress(01:00) = 進捗3
progress(02:00) = 終了

1つ目のforeachコマンドは、「array names」で要素名をリストにしたものをそのまま取り出して出力しています。

2つ目のforeachコマンドは、「array names」が返した要素名のリストを、lsortコマンドで辞書順に整列してから取り出して出力しています。

コメント

タイトルとURLをコピーしました