簡単な背景: 広く使用されている多くの(ほとんどの?)現代のプログラミング言語には、少なくともいくつかのADT(抽象データ型)が共通しています。特に、
文字列(文字で構成されるシーケンス)
リスト(順序付けられた値の集合)、および
マップベースの型(キーを値にマッピングする順序なし配列)
R プログラミング言語では、最初の 2 つはそれぞれcharacter
およびとして実装されますvector
。
私が R を学び始めたとき、ほぼ最初から 2 つのことが明らかでした。1つは、list
が R で最も重要なデータ型である ( R の親クラスであるためdata.frame
)、もう 1 つは、 がどのように機能するかをまったく理解できなかった (少なくとも自分のコードで正しく使用できるほどには理解できなかった) ということです。
まず、R のlist
データ型は、マップ ADT ( dictionary
Python、NSMutableDictionary
Objective C、hash
Perl と Ruby、object literal
Javascript など) の単純な実装であるように思われました。
たとえば、キーと値のペアをコンストラクター (Python ではそうではありませんdict
)に渡すことによって、Python 辞書と同じように作成しますlist
。
x = list("ev1"=10, "ev2"=15, "rv"="Group 1")
また、R リストの項目には、Python 辞書の項目と同じようにアクセスできます (例: ) 。同様に、次のようにして「キー」だけ、または「値」x['ev1']
だけを取得できます。
names(x) # fetch just the 'keys' of an R list
# [1] "ev1" "ev2" "rv"
unlist(x) # fetch just the 'values' of an R list
# ev1 ev2 rv
# "10" "15" "Group 1"
x = list("a"=6, "b"=9, "c"=3)
sum(unlist(x))
# [1] 18
しかし、Rは他のマップ型 ADTlist
とも異なります(私が学んだ言語の中でも)。私の推測では、これは S の初期仕様、つまりデータ/統計 DSL [ドメイン固有言語] をゼロから設計するという意図の結果です。
list
Rと広く使用されている他の言語 (例: Python、Perl、JavaScript) のマッピング型の間には、 3 つの重要な違いがあります。
まず、list
R の は、値にキーが付けられているにもかかわらず、ベクトルと同様に順序付けられたコレクションです (つまり、キーは連続した整数だけでなく、任意のハッシュ可能な値にすることができます)。ほとんどの場合、他の言語のマッピング データ型は順序付けられていません。
2 番目に、関数を呼び出したときlist
に を渡さなかったとしても、またを返した関数に(明示的な) コンストラクタが含まれていなくても、関数から が返される可能性があります (もちろん、実際には、返された結果を の呼び出しでラップすることでこれを処理できます)。list
list
list
unlist
x = strsplit(LETTERS[1:10], "") # passing in an object of type 'character'
class(x) # returns 'list', not a vector of length 2
# [1] list
R の s の3 番目の奇妙な特徴list
: s は別の ADT のメンバーになることはできないようです。そうしようとすると、プライマリ コンテナーが に強制変換されますlist
。例:
x = c(0.5, 0.8, 0.23, list(0.5, 0.2, 0.9), recursive=TRUE)
class(x)
# [1] list
ここでの私の意図は、言語やそのドキュメント化を批判することではありません。同様に、list
データ構造やその動作に何か問題があると示唆しているわけでもありません。私が求めているのは、それらがどのように機能するかについての私の理解を修正し、コードで正しく使用できるようにすることです。
私がもっと理解したいことは次のとおりです。
list
関数呼び出しが(たとえば、strsplit
上記の式)を返すタイミングを決定するルールは何ですか?に明示的に名前を割り当てない場合
list
(例: )、デフォルトの名前は 1 から始まる連続した整数になりますか? (そうだと思いますが、答えが「はい」かどうかは確信がありません。そうでなければ、を呼び出してlist(10,20,30,40)
このタイプの をベクトルに強制変換することはできません。)list
unlist
これら 2 つの異なる演算子、、が同じ結果を返すのはなぜ
[]
でしょう[[]]
か?x = list(1, 2, 3, 4)
どちらの式も「1」を返します。
x[1]
x[[1]]
なぜこれら 2 つの式は同じ結果を返さないのでしょうか?
x = list(1, 2, 3, 4)
x2 = list(1:4)
Rドキュメントを私に紹介しないでください(?list
、R-intro
)--私はそれを注意深く読みましたが、それは私が上で述べたような種類の質問に答えるのに役立ちません。
(最後に、私は最近、CRANで入手可能なRパッケージを知り、使い始めました。hash
これは、S4 クラスを介して従来のマップ型の動作を実装します。このパッケージをぜひお勧めします。
ベストアンサー1
質問の最後の部分に答えると、R のlist
との違いが本当にわかります。vector
なぜこれら 2 つの式は同じ結果を返さないのでしょうか?
x = リスト(1, 2, 3, 4); x2 = リスト(1:4)
リストには、各要素として他のクラスを含めることができます。したがって、最初の要素が文字ベクトル、2 番目の要素がデータ フレームなどのリストを作成できます。この場合、2 つの異なるリストが作成されます。 にはx
、それぞれ長さ 1 のベクトルが 4 つありますx2
。 には、長さ 4 のベクトルが 1 つあります。
> length(x[[1]])
[1] 1
> length(x2[[1]])
[1] 4
したがって、これらは完全に異なるリストです。
Rリストはハッシュマップ各インデックス値を任意のオブジェクトに関連付けることができるという点で、データ構造です。以下は、3 つの異なるクラス (関数を含む) を含むリストの簡単な例です。
> complicated.list <- list("a"=1:4, "b"=1:3, "c"=matrix(1:4, nrow=2), "d"=search)
> lapply(complicated.list, class)
$a
[1] "integer"
$b
[1] "integer"
$c
[1] "matrix"
$d
[1] "function"
最後の要素が検索関数である場合、次のように呼び出すことができます。
> complicated.list[["d"]]()
[1] ".GlobalEnv" ...
これに関する最後のコメントとして、a はdata.frame
実際にはリストであることに注意してください (data.frame
ドキュメントより)。
データフレームは、クラス「"data.frame"」で指定された、一意の行名を持つ同じ行数の変数のリストです。
そのため、列にはdata.frame
異なるデータ型を設定できますが、マトリックスの列には設定できません。例として、ここでは数字と文字を含むマトリックスを作成してみます。
> a <- 1:4
> class(a)
[1] "integer"
> b <- c("a","b","c","d")
> d <- cbind(a, b)
> d
a b
[1,] "1" "a"
[2,] "2" "b"
[3,] "3" "c"
[4,] "4" "d"
> class(d[,1])
[1] "character"
2 番目の列に文字が含まれているため、最初の列のデータ型を数値に変更できないことに注意してください。
> d[,1] <- as.numeric(d[,1])
> class(d[,1])
[1] "character"