簡単な背景:広く使用されている多くの(ほとんど?)現代のプログラミング言語には、少なくとも少数のADT [抽象データ型]が共通してあり、特に、
string(文字で構成されるシーケンス)
list(値の順序付けられたコレクション)、および
マップベースのタイプ(キーを値にマップする順序付けられていない配列)
Rプログラミング言語では、最初の2つはそれぞれcharacter
およびvector
として実装されます。
Rを学習し始めたとき、2つのことは最初からほとんど明らかでした:list
はRの最も重要なデータ型です(Rの親クラスであるためdata.frame
)。少なくとも私のコードでそれらを正しく使用するには十分ではありません。
一つには、Rのlist
データ型は、マップADTの単純な実装であるように思われました(Pythonではdictionary
、Objective CではNSMutableDictionary
、PerlとRubyではhash
、Javascriptではobject literal
など)。
たとえば、キーと値のペアをコンストラクターに渡すことにより、Python辞書と同じように作成します(Pythonではdict
ではなくlist
です):
x = list("ev1"=10, "ev2"=15, "rv"="Group 1")
そして、Python辞書のアイテムと同じように、Rリストのアイテムにアクセスします(例:x['ev1']
)。同様に、次の方法で'keys'または'values'のみを取得できます。
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 list
sもnlike他のマップタイプADT(とにかく学んだ言語の中から)です。私の推測では、これはSの初期仕様の結果である、つまり、データ/統計DSL [ドメイン固有言語]をゼロから設計する意図であるということです。
three R list
sと、広範囲に使用されている他の言語(Python、Perl、JavaScriptなど)のマッピングタイプとの大きな違い:
first、Rのlist
sは、値がキー付きであっても、ベクトルと同様にorderedコレクションです(つまり、キーは連続した整数ではなく、ハッシュ可能な値になります)。ほとんどの場合、他の言語のマッピングデータタイプはnorderedです。
second、関数を呼び出したときにlist
を一度も渡さなかった場合でも、関数からlist
sを返すことができます。また、たとえ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
third Rの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
に明示的に名前を割り当てない場合(たとえば、list(10,20,30,40)
)は、デフォルトの名前は1で始まる連続した整数ですか? (私は推測しますが、答えがイエスであると確信しているわけではありません。そうでなければ、このタイプのlist
をunlist
への呼び出しでベクトルに強制することはできません。)
これらの2つの異なる演算子[]
と[[]]
がsameの結果を返すのはなぜですか?
x = list(1, 2, 3, 4)
両方の式は「1」を返します。
x[1]
x[[1]]
なぜこれら2つの式notは同じ結果を返すのですか?
x = list(1, 2, 3, 4)
x2 = list(1:4)
Rのドキュメント( ?list
、 R-intro
)を指してはいけません上記。
(最後に、 hash
と呼ばれるRパッケージ(CRANで利用可能)を最近学び、使用を開始しました。このパッケージはconventional S4クラスを介してマップタイプの動作を実装しています。このパッケージ。)
質問の最後の部分に対処するために、Rのlist
とvector
の違いを実際に指摘しています。
これら2つの式が同じ結果を返さないのはなぜですか?
x = list(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" ...
これに対する最終的なコメントとして: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列目に文字が含まれているため、1列目のデータ型を数値に変更できないことに注意してください。
> d[,1] <- as.numeric(d[,1])
> class(d[,1])
[1] "character"
あなたの質問に関して、私は順番にそれらに対処し、いくつかの例を挙げましょう。
1)return文が1を足したときにリストが返されます。考えて
R> retList <- function() return(list(1,2,3,4)); class(retList())
[1] "list"
R> notList <- function() return(c(1,2,3,4)); class(notList())
[1] "numeric"
R>
2)名前は単に設定されていません。
R> retList <- function() return(list(1,2,3,4)); names(retList())
NULL
R>
)同じことを返すわけではありません。あなたの例は与える
R> x <- list(1,2,3,4)
R> x[1]
[[1]]
[1] 1
R> x[[1]]
[1] 1
x[1]
はx
の最初の要素を返します。これはx
と同じです。すべてのスカラーは長さ1のベクトルです。一方、x[[1]]
はリストの最初の要素を返します。
4)最後に、2つはそれぞれ4つのスカラーを含むリストと1つの要素を持つリスト(4つの要素のベクトルであること)を作成する間で異なります。
あなたの質問のサブセットを取るためだけに:
この記事 インデックス作成についての[]
と[[]]
の違いについての質問。
手短に言えば、[[]]はリストから単一の項目を選択し、[]
は選択された項目のリストを返します。この例では、x = list(1, 2, 3, 4)'
item 1は単一の整数ですが、x[[1]]
は単一の1を返し、x[1]
は値を1つだけ持つリストを返します。
> x = list(1, 2, 3, 4)
> x[1]
[[1]]
[1] 1
> x[[1]]
[1] 1
1つの理由リストがそうであるように働く(順序付けられている)のはベクトルがしていないどんなノードでもどんなタイプでも含むことができる順序付けられたコンテナの必要性に取り組むことです。リストは、任意の型(ただし長さは同じ)のベクトルのリストであるdata.frame
のベースを形成するなど、Rのさまざまな目的に再利用されます。
これら2つの式が同じ結果を返さないのはなぜですか?
x = list(1, 2, 3, 4); x2 = list(1:4)
@ Shaneの答えに追加するには、同じ結果を得たい場合は、次のことを試してください。
x3 = as.list(1:4)
これはベクトル1:4
をリストに強制変換します。
これにもう1つのポイントを追加するだけです。
Rは hash
パッケージ にあるPythonの辞書と同等のデータ構造を持ちます。あなたはそれについて読むことができます Open Data Groupからのこのブログ記事 。これは簡単な例です:
> library(hash)
> h <- hash( keys=c('foo','bar','baz'), values=1:3 )
> h[c('foo','bar')]
<hash> containing 2 key-value pairs.
bar : 2
foo : 1
使いやすさの点では、hash
クラスはリストと非常によく似ています。しかし、パフォーマンスは大規模なデータセットのほうが優れています。
あなたは言う:
もう1つは、関数を呼び出したときにListを渡さなかった場合でも、関数にListコンストラクタが含まれていない場合でも、関数からリストを返すことができることです。
x = strsplit(LETTERS[1:10], "") # passing in an object of type 'character'
class(x)
# => 'list'
そして、私はあなたがこれが問題であることを示唆していると思います(?)。それが問題ではない理由を説明するためにここにいます:-)。あなたの例は少し単純です、あなたが文字列分割をするとき、あなたは1要素の長さである要素を持つリストを持っているので、あなたはx[[1]]
がunlist(x)[1]
と同じであることを知っています。しかし、strsplit
の結果が各ビンで異なる長さの結果を返すとしたらどうでしょうか。単にベクトルを(リストに対して)返しただけではまったく意味がありません。
例えば:
stuff <- c("You, me, and dupree", "You me, and dupree",
"He ran away, but not very far, and not very fast")
x <- strsplit(stuff, ",")
xx <- unlist(strsplit(stuff, ","))
最初のケース(x
:リストを返す)では、3番目の文字列の2番目の「部分」が何であるかを知ることができます。例えば:x[[3]][2]
。結果が「解明」されたので(xx
)、どうやってunlist
を使って同じことができますか?
x = list(1, 2, 3, 4)
x2 = list(1:4)
all.equal(x,x2)
1:4はc(1,2,3,4)と同じなので、これは同じではありません。それらを同じにしたい場合は、
x = list(c(1,2,3,4))
x2 = list(1:4)
all.equal(x,x2)
それが助けになるなら、私は他のOO以前の言語では "レコード"としてRの "リスト"を考える傾向があります。
"record"という名前は、データベースの専門用語では "records"(別名、行)の標準的な意味と衝突します。そのため、名前が(フィールドの)リストとしてそれ自体を示唆しているのかもしれません。
これら2つの異なる演算子[ ]
と[[ ]]
が同じ結果を返すのはなぜですか?
x = list(1, 2, 3, 4)
[ ]
はサブ設定操作を提供します。一般に、どのオブジェクトのサブセットも、元のオブジェクトと同じ型になります。したがって、x[1]
はリストを提供します。同様にx[1:2]
は元のリストのサブセットなので、リストです。例.
x[1:2]
[[1]] [1] 1
[[2]] [1] 2
[[ ]]
はリストから要素を取り出すためのものです。 x[[1]]
は有効であり、リストから最初の要素を抽出します。 x[[1:2]]
は[[ ]]
のようなサブ設定を提供しないため、[ ]
は無効です。
x[[2]] [1] 2
> x[[2:3]] Error in x[[2:3]] : subscript out of bounds
他の言語のベクトルとハッシュ/配列の概念について
ベクトルはRのアトムです。例えば、rpois(1e4,5)
(5つの乱数)、numeric(55)
(倍精度の長さ-55のゼロベクトル)、およびcharacter(12)
(12の空の文字列)はすべて「基本」です。
リストかベクトルのどちらかがnames
を持つことができます。
> n = numeric(10)
> n
[1] 0 0 0 0 0 0 0 0 0 0
> names(n)
NULL
> names(n) = LETTERS[1:10]
> n
A B C D E F G H I J
0 0 0 0 0 0 0 0 0 0
ベクトルはすべてが同じデータ型である必要があります。これを見て:
> i = integer(5)
> v = c(n,i)
> v
A B C D E F G H I J
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
> class(v)
[1] "numeric"
> i = complex(5)
> v = c(n,i)
> class(v)
[1] "complex"
> v
A B C D E F G H I J
0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i
他の回答やOPの質問自体に見られるように、リストにはさまざまなデータ型を含めることができます。
私は「配列」が可変データ型を含むことができる言語(Ruby、javascript)を見ましたが、例えばC++では「配列」はすべて同じデータ型でなければなりません。私はこれがスピード/効率の問題だと思います:もしあなたがnumeric(1e6)
を持っているなら、あなたはそのサイズとすべての要素の位置を知っています先験的に;もし事物が何らかの未知のスライスに"Flying Purple People Eaters"
を含んでいるかもしれないなら、あなたはそれについての基本的な事実を知るために実際にものをパースしなければなりません。
型が保証されている場合は、特定の標準R演算も意味があります。たとえば、cumsum(1:9)
は意味がありませんが、cumsum(list(1,2,3,4,5,'a',6,7,8,9))
は意味がありません、型がdoubleであることが保証されていない場合。
あなたの2番目の質問に関して:
関数を呼び出したときにListを渡さなかったとしても、関数からリストを返すことができます。
関数は、常に入力されているものとは異なるデータ型を返します。入力としてプロットを受け取らなくても、plot
はプロットを返します。 Arg
は、numeric
を受け入れてもcomplex
を返します。等。
(そしてstrsplit
に関しては、ソースコードは ここ です。)
これはかなり古い質問ですが、Rの最初のステップで不足していた知識、つまりRのオブジェクトとして手にデータを表現する方法、または既存のオブジェクトから選択する方法に正確に触れていると言わなければなりません。 R初心者が最初から「Rボックス内」を考えるのは容易ではありません。
そこで、私自身が以下の松葉杖を使い始めました。これは、どのオブジェクトをどのデータに使用するかを見つけ、基本的には実際の使用法を想像するのに役立ちました。
私は質問に正確な答えを与えていませんが、以下の短いテキストは、Rで始めたばかりで、同様の質問をしている読者を助けるかもしれません。
[
サブセット。[
サブセット。[
サブセットを形成する同じ長さのベクトルの束。list
の巧妙な実装であり、行と列で[
を使用し、さらに[[
を使用してサブセット化できることを本当に認識しました。tree structure
の時点でリストについて考えました。[i]
はブランチ全体を選択して返し、[[i]]
はブランチからアイテムを返します。そして、それはtree like structure
であるため、index sequence
を使用して、[[index_vector]]
を使用して非常に複雑なlist
上のすべての葉をアドレス指定することもできます。リストは単純なものでも非常に複雑なものでもよく、さまざまなタイプのオブジェクトを1つに混在させることができます。したがって、lists
の場合、次の例のように、状況に応じてleaf
を選択する方法が多くなります。
l <- list("aaa",5,list(1:3),LETTERS[1:4],matrix(1:9,3,3))
l[[c(5,4)]] # selects 4 from matrix using [[index_vector]] in list
l[[5]][4] # selects 4 from matrix using sequential index in matrix
l[[5]][1,2] # selects 4 from matrix using row and column in matrix
この考え方は私を大いに助けてくれました。