R 编程,使用自定义脚本(对于每个 i)进行逐行数据帧计算以解决 "bridge game"
R programming, row-wise data frame calculation with custom script (for every i) to solve "bridge game"
我有一个指定“桥牌游戏”的数据框(每一行都是一个独立的游戏),请参阅下面的 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 开始的正整数)和破损板的“缝隙”组成。候选人可以选择他从桥的哪一侧开始步行(升序 = 面板的编号随着步行的进行而增加;或下降 = 面板的编号随着步行的进行而减少)。
可以在此处找到用于更好地理解桥牌游戏的图形(以数据框中的第一行为例):
click here
对于每个桥牌游戏(= 数据框中的行),我们有以下信息(= 列):
- bridge_game$start:整木块的所有起始位置
面板(随机顺序)
- bridge_game$end:整木大片的所有结束位置
面板(随机顺序)
- bridge_game$ascending:以升序(+)或
面板的降序 (-) 顺序
- bridge_game$职位:候选人最终进入了指定的小组
挑战是什么?
我需要编写一个脚本,我可以 运行 在整个数据帧上逐行获得以下输出:
- 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 ) - 结束(i=1 到 n-1) - 1x[n-1])
d) 应用此公式(如果方向为下降“-”且 n < i max):output = end(i=max) - position + 1 - (start(i=n+ 1 到最大值) - 结束(i=n 到 max-1) - 1x[i=max - n])
我希望我的数学就在那里。为了检查正确的输出,我在“bridge_game”数据框中创建了一个“desired_output”列。
感谢您的帮助!
更新:
第 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) 步开始就...
这可能会为您提供第三步所需的信息。我修改了你的 .
的功能
首先,将检查 n
(或 region
)是否为 NA
。如果是,则 start
和 end
之间的 position
不匹配。
否则,您可以包含 if
else
的 2x2 组合,查看 ascending
和 n
。这些方程式使用类似的从 x
中提取值的方法。值得注意的是,看起来你想要 sum
有一系列索引的值(例如,当你说“开始(i=2 到 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
你把这个问题复杂化了。考虑以下实现
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"
这里的关键是我们可以用一个逻辑向量来表示一座桥,其中一个broken/whole面板由F
/T
索引。然后我们只测试停止位置是否在整个面板上。 Return 如果是,则从开始到结束位置的面板总和(损坏的面板不会影响总和,因为它们只是零)否则“不合格”。
对于第 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
我有一个指定“桥牌游戏”的数据框(每一行都是一个独立的游戏),请参阅下面的 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 开始的正整数)和破损板的“缝隙”组成。候选人可以选择他从桥的哪一侧开始步行(升序 = 面板的编号随着步行的进行而增加;或下降 = 面板的编号随着步行的进行而减少)。
可以在此处找到用于更好地理解桥牌游戏的图形(以数据框中的第一行为例): click here
对于每个桥牌游戏(= 数据框中的行),我们有以下信息(= 列):
- bridge_game$start:整木块的所有起始位置 面板(随机顺序)
- bridge_game$end:整木大片的所有结束位置 面板(随机顺序)
- bridge_game$ascending:以升序(+)或 面板的降序 (-) 顺序
- bridge_game$职位:候选人最终进入了指定的小组
挑战是什么? 我需要编写一个脚本,我可以 运行 在整个数据帧上逐行获得以下输出:
- 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 ) - 结束(i=1 到 n-1) - 1x[n-1])
d) 应用此公式(如果方向为下降“-”且 n < i max):output = end(i=max) - position + 1 - (start(i=n+ 1 到最大值) - 结束(i=n 到 max-1) - 1x[i=max - n])
我希望我的数学就在那里。为了检查正确的输出,我在“bridge_game”数据框中创建了一个“desired_output”列。
感谢您的帮助!
更新:
第 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) 步开始就...
这可能会为您提供第三步所需的信息。我修改了你的
首先,将检查 n
(或 region
)是否为 NA
。如果是,则 start
和 end
之间的 position
不匹配。
否则,您可以包含 if
else
的 2x2 组合,查看 ascending
和 n
。这些方程式使用类似的从 x
中提取值的方法。值得注意的是,看起来你想要 sum
有一系列索引的值(例如,当你说“开始(i=2 到 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
你把这个问题复杂化了。考虑以下实现
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"
这里的关键是我们可以用一个逻辑向量来表示一座桥,其中一个broken/whole面板由F
/T
索引。然后我们只测试停止位置是否在整个面板上。 Return 如果是,则从开始到结束位置的面板总和(损坏的面板不会影响总和,因为它们只是零)否则“不合格”。
对于第 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