web-dev-qa-db-ja.com

2つの文字の間のシーケンスを作成する

2つの文字の間にシーケンスを作成したいのですが、"b"および"f"。したがって、出力は

"b" "c" "d" "e" "f"

数字については、私たちはできる

2:6 #which gives output as 
[1] 2 3 4 5 6

これを文字で簡単に行う方法はありますか?

'A'-'Z'から文字のシーケンスを生成する を実行しましたが、これによりすべての文字が生成され、特定の文字間のシーケンスは生成されません。

私の現在の解決策は、

indx <- which(letters %in% c("b", "f")); 
letters[indx[1] : indx[2]]

#[1] "b" "c" "d" "e" "f"

これは機能しますが、これを行う簡単な方法や、私が見逃したパッケージの機能があるかどうか興味がありますか?

注:したくないletters[2:6]私は事前に2と6を知らないので。任意の2文字の間にある可能性があります。

31
Ronak Shah

これは別のベースRオプションになります。

letters[(letters >= "b") & (letters <= "f")]
# [1] "b" "c" "d" "e" "f"
28
r.user.05apr

独自の関数を作成できます:

`%:%` <- function(l, r) {
    intToUtf8(seq(utf8ToInt(l), utf8ToInt(r)), multiple = TRUE)
}

使用法:

"b" %:% "f"
# [1] "b" "c" "d" "e" "f"

"f" %:% "b"
# [1] "f" "e" "d" "c" "b"

"A" %:% "D"
# [1] "A" "B" "C" "D"
17
Sven Hohenstein

matchseqおよびdo.callを使用した別のオプション:

letters[do.call(seq, as.list(match(c("b","f"), letters)))]

与えるもの:

[1] "b" "c" "d" "e" "f"

小文字と大文字の両方で機能するようにこの関数を作成する:

char_seq <- function(lets) {
  switch(all(grepl("[[:upper:]]", lets)) + 1L,
         letters[do.call(seq, as.list(match(lets, letters)))],
         LETTERS[do.call(seq, as.list(match(lets, LETTERS)))])
}

これの出力:

> char_seq(c("b","f"))
[1] "b" "c" "d" "e" "f"

> char_seq(c("B","F"))
[1] "B" "C" "D" "E" "F"

この関数は、入力の正確性をチェックすることで拡張できます。

char_seq <- function(lets) {
  g <- grepl("[[:upper:]]", lets)
  if(length(g) != 2) stop("Input is not of length 2")
  if(sum(g) == 1) stop("Input does not have all lower-case or all upper-case letters")
  switch(all(g) + 1L,
         letters[do.call(seq, as.list(match(lets, letters)))],
         LETTERS[do.call(seq, as.list(match(lets, LETTERS)))])
}

入力が正しくない場合、適切なエラーメッセージが表示されます。

> char_seq(c("B"))
Error in char_seq(c("B")) : Input is not of length 2

> char_seq(c("b","F"))
Error in char_seq(c("b", "F")) : 
  Input does not have all lower-case or all upper-case letters
12
Jaap

次のようなUTFで遊ぶ:

intToUtf8(utf8ToInt("b"):utf8ToInt("f"), multiple = TRUE)
# [1] "b" "c" "d" "e" "f"
10
zx8754

何故なの?

letters[which(letters == 'b') : which(letters == 'f')]

おそらく、文字の生のバージョンを使用してから文字に戻すことを使用して、":"に類似した中置関数を定義できます。

 `%c:%` <- function(x,y) { strsplit( rawToChar(as.raw(
     seq(as.numeric(charToRaw(x)), as.numeric(charToRaw(y))))), "" )[[1]]}
>  'a' %c:% 'g'
[1] "a" "b" "c" "d" "e" "f" "g"

私はこれが「これを行う簡単な方法」の要求を満たしていると主張しているわけではなく、それがより効率的であるとは確信していませんが、いくつかの潜在的に有用な機能を紹介しています。

8
42-

私はそれが眉をひそめていることを知っていますが、ここにeval(parse(...))ソリューションがあります

LETTERS[eval(parse(text = paste(which(LETTERS %in% c('B', 'F')), collapse = ':')))]
#[1] "B" "C" "D" "E" "F"
6
Sotos

まず最初に:あなたのコード

_which(letters %in% c("b", "f"))
_

有効だが複雑な記述方法

_match(c('b', 'f'), letters)
_

(なぜ「複雑な」のか?_%in%_は特定のユースケースのmatchのラッパーであり、数値インデックスを明示的に論理値に変換する、つまりwhichの逆演算だからです。 )

次に、もちろん結果を使用し、_idx[1L] : idx[2L]_を介して範囲に変換することができます。この場合、何も問題はありません。しかし、Rには、パラメーターとしてベクトルを使用して関数を呼び出すという概念を表現する慣用的な方法があります。 _do.call_

_do.call(`:`, as.list(match(c('b', 'f'), letters)))
_

または、同等に:

_do.call(seq, as.list(match(c('b', 'f'), letters)))
_

{purrr}を使用すると、_as.list_なしでも同じことができます。

_purrr::invoke(seq, match(c('b', 'f'), letters))
_

そして最後に、次のサブセットを作成します。

_letters[purrr::invoke(seq, match(c('b', 'f'), letters))]
_
1
Konrad Rudolph