リスト

リストは、Tclの便利なデータ構造の1つですが、リスト操作に関するコマンドは沢山あります。
リストとは、中括弧あるいはダブルクォートを使ってスペースで区切られた文字列のことです。

以下はリストを作成する例ですが、両者の結果は同じになります。

set var {りんご みかん バナナ}
set var
=> りんご みかん バナナ

set var "りんご みかん バナナ"
set var
=> りんご みかん バナナ

また、リスト操作のコマンドでもリストを作成できます。

list, concat, lappend

listコマンドは、引数の文字列からリストを作成します。

set var [list りんご みかん バナナ]
set var
=> りんご みかん バナナ

ただし、引数の中に特殊文字があると、中括弧で取り囲みます。

set var [list \$ \[ abc\ xyz]
set var
=> {$} {[} {abc xyz}

concatコマンドは、引数の文字列からスペースを区切りとしてリストを作成します。

set var [concat "りんご みかん バナナ"]
set var
=> りんご みかん バナナ
set var [concat {りんご みかん バナナ}]
set var
=> りんご みかん バナナ

lappendコマンドは、リストに要素を追加します。
lappendコマンドは、指定された変数が存在しない場合は、作成します。

set var {りんご みかん バナナ}
lappend var メロン いちご
set var
=> りんご みかん バナナ メロン いちご

llength, lindex, lrange

llengthコマンドは、リストの要素数を返します。

set var {りんご みかん バナナ}
llength $var
=> 3

lindexコマンドは、リストの指定されたインデックスの要素を返します。
インデックスは、0からの数字です。

set var {りんご みかん バナナ}
lindex $var 0
=> りんご
lindex $var 1
=> みかん
lindex $var 2
=> バナナ

lrangeコマンドは、リストの指定された範囲の要素をリストで返します。

set var {りんご みかん バナナ}
lrange $var 1 end
=> みかん バナナ

linsert, lreplace

linsertは、リストの指定されたインデックスに要素を挿入したリストを返します。

set var {りんご みかん バナナ}
linsert $var 1 メロン いちご
=> りんご メロン いちご みかん バナナ

lreplaceは、リストの指定されたインデックスの要素を置換したリストを返します。

set var {りんご みかん バナナ}
lreplace $var 1 2 メロン いちご
=> りんご メロン いちご

lreplaceを応用するとリストの指定されたインデックスの要素を削除したリストを返すことができます。

set var {りんご みかん バナナ}
lreplace $var 1 1
=> りんご バナナ

lset

lsetコマンドは、リストの指定されたインデックスの要素を直接変更します。(Tcl8.4から追加されました)

set var {りんご みかん バナナ}
lset var 1 メロン
=> りんご メロン バナナ
set var
=> りんご メロン バナナ

インデックスを省略した場合は、リストの上書き設定になります。
lsetは変数を新規に作成できない点がsetと異なります。

set var {りんご みかん バナナ}
lset var メロン
=> メロン
set var
=> メロン

更に、リストのリストの場合はインデックスを複数指定して変更ができます。

set var {{りんご みかん} {バナナ なし} {すいか いちご}}
lset var 1 1 メロン
=> {りんご みかん} {バナナ メロン} {すいか いちご}
set var
=> {りんご みかん} {バナナ メロン} {すいか いちご}

lsearch

lsearchコマンドは、リストの要素を検索します。
要素が見つかった時は、その要素のインデックスを返し、
見つからなかった時は、-1を返します。

set var {りんご みかん バナナ}
lsearch $var みかん
=> 1
lsearch $var メロン
=> -1

-globあるいは-regexpオプションを使うと正規表現を使って検索できます。

set var {りんご みかん バナナ}
lsearch -glob $var み*
=> 1
set var {りんご みかん バナナ}
lsearch -regexp $var み+
=> 1

lsort

lsortコマンドは、リストの要素をソートしたリストを返します。
以下のオプションがあります。

set var {りんご みかん バナナ}
lsort -dictionary $var
=> みかん りんご バナナ
set var {{1 りんご} {2 みかん} {3 バナナ}}
lsort -decreasing -integer -index 0 $var
=> {3 バナナ} {2 みかん} {1 りんご}
set var {りんご みかん バナナ りんご}
lsort -unique $var
=> みかん りんご バナナ

split, join

splitコマンドは、指定された区切り文字で文字列を分割したリストを返します。
区切り文字を省略した場合は、スペースを区切り文字とします。

set var {りんご:みかん:バナナ}
split $var :
=> りんご みかん バナナ

joinコマンドは、splitの逆で、リストの各要素に指定された区切り文字を連結した文字列を返します。

set var {りんご みかん バナナ}
join $var :
=> りんご:みかん:バナナ


リストは、Tclの便利な機能の1つですが、似たようなコマンドがあり、
混乱することもあるので整理してみました。

listとconcat

listとconcatコマンドは似ていますが、わずかな違いがあるので注意が必要です。
以下の例を見比べると、concatはリストレベルを1つだけ取り除くことがわかります。

list concat
list a b {c d e} {f {g h}}
=>a b {c d e} {f {g h}}
concat a b {c d e} {f {g h}}
=>a b c d e f {g h}

evalとの組み合わせ

evalコマンドは、引数をコマンドとして実行するコマンドですが、
concatと同じくリストレベルを1つだけ取り除きます。
evalとconcatを組み合わせるとリストレベルを2つ取り除きます。

eval+list eval+concat
eval list a b {c d e} {f {g h}}
=>a b c d e f {g h}
eval concat a b {c d e} {f {g h}}
=>a b c d e f g h

substとダブルクォート

substコマンドとダブルクォートもコマンド展開と変数展開を行うという意味では、
concatと同じくリストレベルを1つだけ取り除きます。
substは、引数をコマンドとして実行しない以外はevalと同じです。

list concat subst ダブルクォート
set x {1 2}
=>1 2
set y [list $x 3]
=>{1 2} 3
set x {1 2}
=>1 2
set y [concat $x 3]
=>1 2 3
set x {1 2}
=>1 2
subst {$x 3}
=>1 2 3
set x {1 2}
=>1 2
set y "$x 3"
=>1 2 3

注意

listとconcatは、データによっては同じ結果を返す場合もあるので厄介です。
特にlist,concat,eval,subst,ダブルクォートを組み合わせると結果が予測しにくくなり、
これによってスクリプトにバグが組み込まれてしまう可能性があります。
十分注意して使いましょう。