Rプログラミング、「ブリッジゲーム」を解決するためのカスタムスクリプト(すべてのi)を使用した行単位のデータフレーム計算
「ブリッジゲーム」(すべての行が1つの独立したゲーム)を指定するデータフレームがあります。以下の4つのゲームの最小例を参照してください。
start <- list(c("10","15","5"), c("5") ,c("11","6"),c("6","11"))
end <- list(c("7","17","11"), c("10"), c("8","12"),c("8","12"))
ascending <- c("+","-","+","-")
position <- c(11,6,9,8)
desired_output <- c(5,5,"disqualified",3)
bridge_game <- data.frame(start = I(start), end = I(end), ascending = ascending, position = position, desired_output = desired_output)
bridge_game
ブリッジゲームはどのように機能しますか?世界中の候補者がブリッジゲームチャレンジに参加し、すべてのブリッジゲームのデータをデータフレームに収集しました。すべてのブリッジは、番号が付けられた木製パネル(必ずしも1から始まる必要のない正の整数)と壊れたパネルの「ギャップ」で構成されています。候補者は、橋のどちら側から歩行を開始するかを選択できます(昇順=歩行が進むにつれてパネルの番号が増加する、または下降=歩行が進むにつれてパネルの番号が減少する)。
ブリッジゲームをよりよく理解するためのグラフィックはここにあります(データフレームの1行目に例示されています):ここをクリックしてください
すべてのブリッジゲーム(=データフレームの行)について、次の情報(=列)があります。
- bridge_game $ start:木製パネル全体のトラクトのすべての開始位置(ランダムな順序)
- bridge_game $ end:木製パネル全体のトラクトのすべての終了位置(ランダムな順序)
- bridge_game $ ascending:パネルの昇順(+)または降順(-)で橋を渡ります
- bridge_game $ position:候補は示されたパネルに行き着きました
課題は何ですか?次の出力を取得するには、データフレーム全体で行方向に実行できるスクリプトを作成する必要があります。
- bridge_game $ desired_output:候補者が川に落ちたかどうかをテストします(パネルが壊れて「失格」になりました)。そして、彼が失格にならない場合は、候補者の散歩で覆われた木製パネル全体の数を計算する必要があります(壊れたパネルはカウントされません)。
重要なのは、それは木製パネルの全領域の任意の数iで機能するはずです。
より正確に言うと、要求されたRスクリプトがどのように動作するかを以下に段階的に説明します。
0)解決しました
a)文字のリストを列bridge_game $ startおよびbridge_game $ endの数値リストに変換します。
b)i(木製パネル全体のトラクトの数。iはすべての行で1からi = maxになります)を計算し、開始位置と終了位置を並べ替えて、すべてのiの正しい開始値と終了値を取得します。
1)位置が壊れたパネルにあるかどうかをテストします:end(i = 1 to max-1)> position> start(i = 2 to max)->テストされたペアのいずれかに対してTRUEの場合-> "disqualified"
2)いいえの場合、指定された位置がパネル全体のどの領域にあるかをテストします(i = n):start(i = 1 to max)<= position <= end(i = 1 to max)-> TRUEの場合i(= n)
3)
a)次の式を適用します(方向が「+」を昇順でn = 1の場合):output = position --start(i = 1)+ 1
b)次の式を適用します(方向が「-」で下降し、n = i maxの場合):output = end(i = max)-position + 1
c)次の式を適用します(方向が「+」を昇順でn> 1の場合):output = position --start(i = 1)+ 1-(start(i = 2 to n)-end(i = 1 to n- 1)-1x [n-1])
d)次の式を適用します(方向が「-」で下降し、n <i maxの場合):output = end(i = max)-position + 1-(start(i = n + 1 to max)-end(i = n最大1)-1x [i = max-n])
私はそこに数学があったことを願っています。正しい出力を確認するために、「bridge_game」データフレームに「desired_output」列を作成しました。
ご協力いただきありがとうございます!
回答
ステップ3のより簡単な解決策があるようです。関数npanels
は、パネル番号からベクトルを作成し、その中のプレーヤーのストップの位置を決定します。移動方向が正の場合(ascending
変数は"+"
)、これが目的のソリューションです。負の場合、目的の値はこのベクトルの長さに基づいて計算されます。
start <- list(c(5,10,15), c(5) ,c(6,11),c(6,11))
end <- list(c(7,11,17), c(10), c(8,12),c(8,12))
position <- c(11,6,9,8)
ascending <- c("+","-","+","-")
game <- data.frame(start = I(start), end = I(end), position = position, ascending = ascending)
npanels <- function (data) {
v <- unlist(Map(":",
unlist(data[["start"]]),
unlist(data[["end"]])))
p <- which(v == data[["position"]])
l <- length(v)
b <- 1+l-p
d <- data[["ascending"]]
n <- ifelse(d == "+", p, b)
n <- if(is.na(n)) "disqualified" else n
return(n)
}
game$solution <- apply(game, 1, npanels)
game
あなたはこの問題を過度に複雑にしました。次の実装を検討してください
parse_pos <- function(x) sort(as.integer(x))
construct_bridge <- function(starts, ends) {
starts <- parse_pos(starts); ends <- parse_pos(ends)
bridge <- logical(tail(ends, 1L))
whole_panels <- sequence(ends - starts + 1L, starts)
bridge[whole_panels] <- TRUE
bridge
}
count_steps <- function(bridge, direction, stop_pos) {
if (isFALSE(bridge[[stop_pos]]))
return("disqualified")
start_pos = c("+" = 1L, "-" = length(bridge))[[direction]]
sum(bridge[start_pos:stop_pos])
}
play_games <- function(starts, ends, direction, stop_pos) {
mapply(function(s, e, d, sp) {
bridge <- construct_bridge(s, e)
count_steps(bridge, d, sp)
}, starts, ends, direction, stop_pos)
}
出力
> with(bridge_game, play_games(start, end, ascending, position))
[1] "5" "5" "disqualified" "3"
ここで重要なのは、論理ベクトルを使用してブリッジを表すことができることです。ブリッジでは、壊れた/パネル全体がF
/でインデックス付けされT
ます。次に、停止位置がパネル全体にあるかどうかをテストします。パネルの合計を開始位置から終了位置まで返す場合(壊れたパネルはゼロであるため合計に影響しません)、そうでない場合は「失格」になります。
これにより、3番目のステップに必要なものが提供される場合があります。他の投稿から関数を変更しました。
まず、n
(またはregion
)がであるかどうかを確認しNA
ます。それがある場合は、のために一致するものがなかったposition
間start
とend
。
そうしないと、2×2の組み合わせ含めることができますif
else
見てをascending
してn
。方程式は、からの値の同様の抽出を使用しますx
。注目すべきsum
は、インデックスの範囲がある値が必要なようです(たとえば、「start(i = 2 to n)」と言うとsum
、などの値が必要ですsum(start[2:n])
)。
これにより、方程式が必要に応じて直接コードに変換されることに注意してください。ただし、他の回答で説明されているロジックに基づいた、より単純な代替手段があります。
start <- list(c(5,10,15), c(5) ,c(6,11),c(6,11))
end <- list(c(7,11,17), c(10), c(8,12),c(8,12))
ascending <- c("+","-","+","-")
imax <- c(3,1,2,2)
position <- c(11,6,9,8)
example <- data.frame(start = I(start), end = I(end), ascending = ascending, imax = imax, position = position)
my_fun <- function(x) {
n <- NA
out <- NA
start <- as.numeric(unlist(x[["start"]]))
end <- as.numeric(unlist(x[["end"]]))
for (i in 1:x[["imax"]]) {
if (between(x[["position"]], start[i], end[i])) n <- i
}
if (!is.na(n)) {
if (x[["ascending"]] == "+") {
if (n == 1) {
out <- x[["position"]] - start[1] + 1
} else if (n > 1) {
out <- x[["position"]] - start[1] + 1 - (sum(start[2:n]) - sum(end[1:(n-1)]) - (n - 1))
}
} else if (x[["ascending"]] == "-") {
if (n == x[["imax"]]) {
out <- end[x[["imax"]]] - x[["position"]] + 1
} else if (n < x[["imax"]]) {
out <- end[x[["imax"]]] - x[["position"]] + 1 - (sum(start[(n+1):x[["imax"]]]) - sum(end[n:(x[["imax"]] - 1)]) - (x[["imax"]] - n))
}
}
}
out
}
example$desired_output <- apply(example, 1, my_fun)
出力
start end ascending imax position desired_output
1 5, 10, 15 7, 11, 17 + 3 11 5
2 5 10 - 1 6 5
3 6, 11 8, 12 + 2 9 NA
4 6, 11 8, 12 - 2 8 3
更新:
ステップ0)が完了しました:
#Change to numeric
bridge_game$start <- lapply(bridge_game$start, as.numeric)
bridge_game$end <- lapply(bridge_game$end, as.numeric)
#Calculate number of tracts of whole wooden panels
bridge_game$tracts <- lapply(bridge_game$start, length)
#Sort start and end positions
bridge_game$start <- lapply(bridge_game$start, sort)
bridge_game$end <- lapply(bridge_game$end, sort)
#Calculate number of tracts of whole wooden panels
bridge_game$tracts <- lapply(bridge_game$start, length)
ステップ1)から苦労しています...