Поскольку вы хотите поместить его в уценку, я думаю, можно с уверенностью сказать, что размер таблицы управляемый, поэтому производительность не является фактором. (Edit # 3: У меня были некоторые мелкие ошибки, связанные с наличием имен строк, так чтобы упростить вещи, я буду полностью удалить их из выборки данных.)
mtcars$rowname <- rownames(mtcars)
rownames(mtcars) <- NULL
mtcars <- mtcars[,c(ncol(mtcars), 1:(ncol(mtcars)-1))]
head(mtcars)
# rowname mpg cyl disp hp drat wt qsec vs am gear carb
# 1 Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
# 2 Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
# 3 Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
# 4 Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
# 5 Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
# 6 Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1
Теперь работа:
dashes <- paste(rep("---", ncol(mtcars)), collapse = "|")
txt <- capture.output(
write.table(mtcars, stdout(), quote = FALSE, sep = "|", row.names = FALSE)
)
txt2 <- sprintf("|%s|", c(txt[1], dashes, txt[-1]))
head(txt2)
# [1] "|rowname|mpg|cyl|disp|hp|drat|wt|qsec|vs|am|gear|carb|"
# [2] "|---|---|---|---|---|---|---|---|---|---|---|---|"
# [3] "|Mazda RX4|21|6|160|110|3.9|2.62|16.46|0|1|4|4|"
# [4] "|Mazda RX4 Wag|21|6|160|110|3.9|2.875|17.02|0|1|4|4|"
# [5] "|Datsun 710|22.8|4|108|93|3.85|2.32|18.61|1|1|4|1|"
# [6] "|Hornet 4 Drive|21.4|6|258|110|3.08|3.215|19.44|1|0|3|1|"
Если вас беспокоит выравнивание, вы можете проверить на character
(и, возможно, другие, к вам). При этом используется выравнивание строки формата уценки таблицы:
(ischar <- vapply(mtcars, is.character, logical(1)))
# rowname mpg cyl disp hp drat wt qsec vs am gear carb
# TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
dashes <- paste(ifelse(ischar, ":--", "--:"), collapse = "|")
txt <- capture.output(write.table(mtcars, stdout(), quote = FALSE, sep = "|", row.names = FALSE))
txt2 <- sprintf("|%s|", c(txt[1], dashes, txt[-1]))
head(txt2)
# [1] "|rowname|mpg|cyl|disp|hp|drat|wt|qsec|vs|am|gear|carb|"
# [2] "|:--|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|"
# [3] "|Mazda RX4|21|6|160|110|3.9|2.62|16.46|0|1|4|4|"
# [4] "|Mazda RX4 Wag|21|6|160|110|3.9|2.875|17.02|0|1|4|4|"
# [5] "|Datsun 710|22.8|4|108|93|3.85|2.32|18.61|1|1|4|1|"
# [6] "|Hornet 4 Drive|21.4|6|258|110|3.08|3.215|19.44|1|0|3|1|"
И когда вы, наконец, готовы сохранить, использовать cat(txt2, file = "sometable.md")
(или writeLines
).
Редактировать # 1: обратите внимание, что другие предлагаемые ответы (включая шахты выше) не обращаются символов трубы в пределах содержания:
mtcars$mpg[1] <- "2|1.0"
ischar <- vapply(mtcars, is.character, logical(1))
dashes <- paste(ifelse(ischar, ":--", "--:"), collapse = "|")
txt <- capture.output(write.table(mtcars, stdout(), quote = FALSE, sep = "|", row.names = FALSE))
txt2 <- sprintf("|%s|", c(txt[1], dashes, txt[-1]))
head(txt2, n = 3)
# [1] "|rowname|mpg|cyl|disp|hp|drat|wt|qsec|vs|am|gear|carb|"
# [2] "|:--|:--|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|"
# [3] "|Mazda RX4|2|1.0|6|160|110|3.9|2.62|16.46|0|1|4|4|"
### ^this is the problem
Вы можете избежать его вручную на все персонаж (или добавить в факторах тоже) колонки:
ischar <- vapply(mtcars, is.character, logical(1))
mtcars[ischar] <- lapply(mtcars[ischar], function(x) gsub("\\|", "|", x))
dashes <- paste(ifelse(ischar, ":--", "--:"), collapse = "|")
txt <- capture.output(write.table(mtcars, stdout(), quote = FALSE, sep = "|", row.names = FALSE))
txt2 <- sprintf("|%s|", c(txt[1], dashes, txt[-1]))
head(txt2, n = 3)
# [1] "|rowname|mpg|cyl|disp|hp|drat|wt|qsec|vs|am|gear|carb|"
# [2] "|:--|:--|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|"
# [3] "|Mazda RX4|2|1.0|6|160|110|3.9|2.62|16.46|0|1|4|4|"
### ^^^^^^ this is the pipe, interpreted correctly in markdown
Это не очень хорошо работает, когда труба находится в пределах блока кода, хотя обходной путь был предложен здесь: https://stackoverflow.com/a/17320389/3358272
На этом этапе, как предложил @alistaire, вы несколько переопределяете knitr::kable
. Если на то пошло, просто возьмите knitr/R/table.R
) и используйте kable_markdown
, что делает выпадение трубы для вас. Требуется character matrix
, а не data.frame
, поэтому kable_markdown(as.matrix(mtcars))
. Вы не можете просто захватить одну функцию, поскольку она использует несколько вспомогательных функций также в этом файле. Вы можете, конечно, сократить некоторые функции, в том числе kable
, который требует функций в других файлах.
Edit # 2: так как вы сказали, renjin не поддерживает *apply
функции (комментарий предполагает, что это неправильно, но я буду продолжать ради аргумента), вот for
-loop реализация, которая включает в себя выравнивание и |
-escaping:
mtcars$mpg[1] <- "2|1.0" # just a reminder that it's here
dashes <- rep("--:", length(mtcars))
for (i in seq_along(mtcars)) {
if (is.character(mtcars[[i]]) || is.factor(mtcars[[i]])) {
mtcars[[i]] <- gsub("\\|", "|", mtcars[[i]])
dashes[i] <- ":--"
}
}
txt <- capture.output(write.table(mtcars, stdout(), quote = FALSE, sep = "|", row.names = FALSE))
txt2 <- sprintf("|%s|", c(txt[1], paste(dashes, collapse = "|"), txt[-1]))
head(txt2, n = 3)
# [1] "|rowname|mpg|cyl|disp|hp|drat|wt|qsec|vs|am|gear|carb|"
# [2] "|:--|:--|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|"
# [3] "|Mazda RX4|2|1.0|6|160|110|3.9|2.62|16.46|0|1|4|4|"
Для записи, моя *apply
и for
-loop реализации эффективна такая же производительность, в то время как решение @ alistaire является более чем вдвое быстрее (с mtcars
):
Unit: microseconds
expr min lq mean median uq max neval
apply_noalign 917.881 947.9665 1031.9288 971.3060 1041.5050 1999.499 100
apply_align 945.960 975.1350 1083.2856 995.7390 1063.7500 3523.101 100
apply_align_pipes 1110.429 1148.5360 1255.5460 1176.9815 1275.2600 1905.778 100
forloop 1188.104 1217.0950 1309.2549 1261.2205 1342.3600 2979.010 100
alistaire 451.830 473.7105 511.5778 496.1370 518.5645 827.443 100
alistaire_pipes 593.687 626.6900 718.6898 652.7645 700.5360 5460.970 100
Я использовал его оригинальную функцию для alistaire
и добавил простой gsub
для alistaire_pipes
. Может быть более эффективный способ сделать это, но (а) простой/прямой ход хорош, и (б) я думаю, что ваши таблицы будут достаточно маленькими, если истинная производительность не будет движущей силой.
Существует [существенное обсуждение] (https://groups.google.com/forum/?nomobile=true#!searchin/pandoc-discuss/csv%7Csort:relevance/pandoc-discuss/znGQ62WpWrg/lFpgTPZzGgAJ) о таблицах CSV в группе pandoc google, включая фильтр pandoc. Я не знаю его состояния, но вы можете это проверить. – r2evans
apply(), lapply(), sapply(), mapply(), vapply() - все функции из базового пакета, который всегда доступен изнутри Renjin. – akbertram