Поскольку этот вопрос все еще активен, вот еще один подход:
/**
* Performs a deep merge of objects and returns new object. Does not modify
* objects (immutable) and merges arrays via concatenation.
*
* @param {...object} objects - Objects to merge
* @returns {object} New object with merged key/values
*/
function mergeDeep(...objects) {
const isObject = obj => obj && typeof obj === 'object';
return objects.reduce((prev, obj) => {
Object.keys(obj).forEach(key => {
const pVal = prev[key];
const oVal = obj[key];
if (Array.isArray(pVal) && Array.isArray(oVal)) {
prev[key] = pVal.concat(...oVal);
}
else if (isObject(pVal) && isObject(oVal)) {
prev[key] = mergeDeep(pVal, oVal);
}
else {
prev[key] = oVal;
}
});
return prev;
}, {});
}
// Test objects
const obj1 = {
a: 1,
b: 1,
c: { x: 1, y: 1 },
d: [ 1, 1 ]
}
const obj2 = {
b: 2,
c: { y: 2, z: 2 },
d: [ 2, 2 ],
e: 2
}
const obj3 = mergeDeep(obj1, obj2);
// Out
console.log(obj3);
UseMethod("t")
сообщает вам, что t()
является общей функцией ( S3 ), которая имеет методы для разных классов объектов.
Для классов S3 вы можете использовать функцию methods
для перечисления методов для определенной общей функции или класса.
> methods(t)
[1] t.data.frame t.default t.ts*
Non-visible functions are asterisked
> methods(class="ts")
[1] aggregate.ts as.data.frame.ts cbind.ts* cycle.ts*
[5] diffinv.ts* diff.ts kernapply.ts* lines.ts
[9] monthplot.ts* na.omit.ts* Ops.ts* plot.ts
[13] print.ts time.ts* [<-.ts* [.ts*
[17] t.ts* window<-.ts* window.ts*
Non-visible functions are asterisked
«Невидимые функции являются звездочками» означает, что функция не экспортируется из пространства имен пакета. Вы можете просмотреть исходный код с помощью функции :::
(т. Е. stats:::t.ts
) или с помощью getAnywhere()
. getAnywhere()
полезен, потому что вам не нужно знать, из какого пакета появилась функция.
> getAnywhere(t.ts)
A single object matching ‘t.ts’ was found
It was found in the following places
registered S3 method for t from namespace stats
namespace:stats
with value
function (x)
{
cl <- oldClass(x)
other <- !(cl %in% c("ts", "mts"))
class(x) <- if (any(other))
cl[other]
attr(x, "tsp") <- NULL
t(x)
}
<bytecode: 0x294e410>
<environment: namespace:stats>
Система S4 - это более новый метод отправки и является альтернативой системе S3. Вот пример функции S4:
> library(Matrix)
Loading required package: lattice
> chol2inv
standardGeneric for "chol2inv" defined from package "base"
function (x, ...)
standardGeneric("chol2inv")
<bytecode: 0x000000000eafd790>
<environment: 0x000000000eb06f10>
Methods may be defined for arguments: x
Use showMethods("chol2inv") for currently available ones.
Вывод уже содержит много информации. standardGeneric
является индикатором функции S4. Предлагается метод для просмотра определенных методов S4:
> showMethods(chol2inv)
Function: chol2inv (package base)
x="ANY"
x="CHMfactor"
x="denseMatrix"
x="diagonalMatrix"
x="dtrMatrix"
x="sparseMatrix"
getMethod
может использоваться для просмотра исходного кода одного из методов:
> getMethod("chol2inv", "diagonalMatrix")
Method Definition:
function (x, ...)
{
chk.s(...)
tcrossprod(solve(x))
}
<bytecode: 0x000000000ea2cc70>
<environment: namespace:Matrix>
Signatures:
x
target "diagonalMatrix"
defined "diagonalMatrix"
также методы с более сложными сигнатурами для каждого метода, например
require(raster)
showMethods(extract)
Function: extract (package raster)
x="Raster", y="data.frame"
x="Raster", y="Extent"
x="Raster", y="matrix"
x="Raster", y="SpatialLines"
x="Raster", y="SpatialPoints"
x="Raster", y="SpatialPolygons"
x="Raster", y="vector"
Чтобы увидеть исходный код для одного из этих методов, должна быть поставлена целая сигнатура, например
getMethod("extract" , signature = c( x = "Raster" , y = "SpatialPolygons") )
Недостаточно предоставить частичную подпись
getMethod("extract",signature="SpatialPolygons")
#Error in getMethod("extract", signature = "SpatialPolygons") :
# No method found for function "extract" and signature SpatialPolygons
В случае ts.union
, .cbindts
и .makeNamesTs
являются невыполненными функциями из пространство имен stats
. Вы можете просмотреть исходный код невыгруженных функций с помощью оператора :::
или getAnywhere
.
> stats:::.makeNamesTs
function (...)
{
l <- as.list(substitute(list(...)))[-1L]
nm <- names(l)
fixup <- if (is.null(nm))
seq_along(l)
else nm == ""
dep <- sapply(l[fixup], function(x) deparse(x)[1L])
if (is.null(nm))
return(dep)
if (any(fixup))
nm[fixup] <- dep
nm
}
<bytecode: 0x38140d0>
<environment: namespace:stats>
Обратите внимание, что «скомпилированный» не обратитесь к байт-компилированному R-коду, созданному пакетом компилятора. Строка <bytecode: 0x294e410>
в приведенном выше выводе указывает, что функция скомпилирована в байтах, и вы все еще можете просмотреть источник из командной строки R.
Функции, вызывающие .C
, .Call
, .Fortran
, .External
, .Internal
или .Primitive
вызывают точки входа в скомпилированном коде, поэтому вам нужно будет искать источники скомпилированного кода, если вы хотите полностью понять эту функцию. Это зеркало GitHub исходного кода R - достойное место для запуска. Функция pryr::show_c_source
может быть полезным инструментом, так как она приведет вас непосредственно на страницу GitHub для вызовов .Internal
и .Primitive
. Пакеты могут использовать .C
, .Call
, .Fortran
и .External
; но не .Internal
или .Primitive
, поскольку они используются для вызова функций, встроенных в интерпретатор R.
Вызовы некоторых из вышеперечисленных функций могут использовать объект вместо символьной строки для ссылки на скомпилированные функция. В этих случаях объект имеет класс "NativeSymbolInfo"
, "RegisteredNativeSymbol"
или "NativeSymbol"
; и печать объекта дает полезную информацию. Например, optim
вызывает .External2(C_optimhess, res$par, fn1, gr1, con)
(обратите внимание, что это C_optimhess
, а не "C_optimhess"
). optim
находится в пакете статистики, поэтому вы можете ввести stats:::C_optimhess
, чтобы просмотреть информацию о вызываемой скомпилированной функции.
Если вы хотите просмотреть скомпилированный код в пакете, вам нужно будет загрузить / распаковать исходный код пакета. Установленных двоичных файлов недостаточно. Исходный код пакета доступен из одного и того же CRAN (или совместимого с CRAN) репозитория, из которого первоначально был установлен пакет. Функция download.packages()
может получить источник пакета для вас.
download.packages(pkgs = "Matrix",
destdir = ".",
type = "source")
Это загрузит исходную версию пакета Matrix и сохранит соответствующий файл .tar.gz
в текущем каталоге. Исходный код для скомпилированных функций можно найти в каталоге src
несжатого и нераспределенного файла. Разомкнутый и необратимый шаг можно выполнить за пределами R
или из R
с помощью функции untar()
. Можно объединить шаг загрузки и расширения в один вызов (обратите внимание, что один и тот же пакет может быть загружен и распакован таким образом):
untar(download.packages(pkgs = "Matrix",
destdir = ".",
type = "source")[,2])
В качестве альтернативы, если разработка пакета (например, через GitHub , R-Forge или RForge.net ), вы можете, вероятно, просмотреть исходный код онлайн.
Некоторые пакеты считаются «базовыми» пакетами. Эти пакеты поставляются с R, и их версия блокируется версией R. Примеры включают base
, compiler
, stats
и utils
. Таким образом, они недоступны в виде отдельных загружаемых пакетов на CRAN, как описано выше. Скорее, они являются частью дерева источников R в отдельных каталогах пакетов в /src/library/
. Как получить доступ к источнику R, описан в следующем разделе.
Если вы хотите просмотреть встроенный код в интерпретаторе R, вы необходимо будет загрузить / распаковать источники R; или вы можете просмотреть источники в Интернете через репозиторий R Subversion или github mirror Winston Chang
.
Новая статья R Uwe Ligges [PDF] (стр. 43) является хорошей общей ссылкой о том, как просматривать исходный код для функций .Internal
и .Primitive
. Основные шаги - сначала искать имя функции в src/main/names.c
, а затем искать имя «C-entry» в файлах в src/main/*
.
В R edit
new_optim <- edit(optim)
есть очень удобная функция. Он откроет исходный код optim
, используя редактор, указанный в R options
, а затем вы можете его редактировать и назначьте измененную функцию new_optim
. Мне очень нравится эта функция, чтобы просматривать код или отлаживать код, например, печатать некоторые сообщения или переменные или даже назначать их глобальным переменным для дальнейшего исследования (конечно, вы можете использовать debug
).
Если вы просто хотите просмотреть исходный код и не хотите, чтобы на вашей консоли был напечатан раздражающий длинный исходный код, вы можете использовать
invisible(edit(optim))
. Ясно, что это невозможно использовать для просмотра C / C ++ или Исходный код Fortran.
BTW, edit
может открывать другие объекты, такие как список, матрица и т. Д., Который также показывает структуру данных с атрибутами. Функция de
может быть использована для открытия редактора Excel (если он поддерживает GUI) для изменения рамки матрицы или данных и возврата нового. Иногда это удобно, но его следует избегать в обычном случае, особенно когда вы крупнее.
View([function_name])
- например. View(mean)
Обязательно используйте верхний регистр [V]. В редакторе откроется код только для чтения.
Пока функция написана в чистом R не C / C ++ / Fortran, можно использовать следующее. В противном случае лучшим способом является отладка и использование «прыгать в»:
> functionBody(functionName)
body
. identical(functionBody, body)
- TRUE
.
– Joshua Ulrich
24 January 2017 в 19:26
base::body
и methods::functionBody
, хотя они не поддаются описанию. body
также можно было бы переопределить: rdocumentation.org/search?q=body
– Moody_Mudskipper
10 November 2017 в 23:03
Для непримитивных функций база R включает в себя функцию, называемую body()
, которая возвращает тело функции. Например, источник функции print.Date()
можно просмотреть:
body(print.Date)
выдает следующее:
{
if (is.null(max))
max <- getOption("max.print", 9999L)
if (max < length(x)) {
print(format(x[seq_len(max)]), max = max, ...)
cat(" [ reached getOption(\"max.print\") -- omitted",
length(x) - max, "entries ]\n")
}
else print(format(x), max = max, ...)
invisible(x)
}
Если вы работаете в скрипте и хотите, чтобы код функции как символ символа, вы можете получить его.
capture.output(print(body(print.Date)))
доставит вам:
[1] "{"
[2] " if (is.null(max)) "
[3] " max <- getOption(\"max.print\", 9999L)"
[4] " if (max < length(x)) {"
[5] " print(format(x[seq_len(max)]), max = max, ...)"
[6] " cat(\" [ reached getOption(\\\"max.print\\\") -- omitted\", "
[7] " length(x) - max, \"entries ]\\n\")"
[8] " }"
[9] " else print(format(x), max = max, ...)"
[10] " invisible(x)"
[11] "}"
Зачем мне это делать? Я создал пользовательский объект S3 (x
, где class(x) = "foo"
) на основе списка. Один из участников списка (называемый «fun») был функцией, и я хотел print.foo()
отобразить исходный код функции с отступом. Таким образом, я получил следующий фрагмент в print.foo()
:
sourceVector = capture.output(print(body(x[["fun"]])))
cat(paste0(" ", sourceVector, "\n"))
, который отступы и отображает код, связанный с x[["fun"]]
.
getAnywhere
. Или вы можете просто использовать обратные выходы, если вы уже знаете имя оператора: `%in%`
.
– Joshua Ulrich
1 December 2015 в 21:32
getAnywhere
также упоминается в вашем ответе, но я думаю, что конкретная ссылка на инфикс полезна для будущей ссылки на этот ответ. Я читал эту страницу много раз и все еще был немного озадачен, пытаясь найти код для таких функции на некоторое время - и я не думал, что он вписывается в поток любого другого ответа (который оба используют getAnywhere
для другой цели).
– MichaelChirico
1 December 2015 в 21:37
Он обнаруживается при отладке с помощью функции debug (). Предположим, вы хотите увидеть базовый код в функции транспонирования t (). Просто набрав «t», не обнаруживается много.
>t
function (x)
UseMethod("t")
<bytecode: 0x000000003085c010>
<environment: namespace:base>
Но, используя «debug (functionName)», он показывает базовый код, без внутренних элементов.
> debug(t)
> t(co2)
debugging in: t(co2)
debug: UseMethod("t")
Browse[2]>
debugging in: t.ts(co2)
debug: {
cl <- oldClass(x)
other <- !(cl %in% c("ts", "mts"))
class(x) <- if (any(other))
cl[other]
attr(x, "tsp") <- NULL
t(x)
}
Browse[3]>
debug: cl <- oldClass(x)
Browse[3]>
debug: other <- !(cl %in% c("ts", "mts"))
Browse[3]>
debug: class(x) <- if (any(other)) cl[other]
Browse[3]>
debug: attr(x, "tsp") <- NULL
Browse[3]>
debug: t(x)
EDIT: debugonce () выполняет то же самое без использования undebug ()
debugonce
вместо debug
в этом случае.
– Joshua Ulrich
18 August 2014 в 21:20
В дополнение к другим ответам на этот вопрос и его дубликатам, вот хороший способ получить исходный код для функции пакета без необходимости знать, в каком пакете он находится. если нам нужен источник для randomForest::rfcv()
:
Чтобы просмотреть / отредактировать его во всплывающем окне:
edit(getAnywhere('rfcv'), file='source_rfcv.r')
Для перенаправления на отдельный файл:
capture.output(getAnywhere('rfcv'), file='source_rfcv.r')
Вы также можете попытаться использовать print.function()
, который является S3 generic, чтобы получить функцию записи в консоли.
print.function()
- метод S3 i>. Общий - print()
. И вообще не рекомендуется напрямую обращаться к методам. Это побеждает всю цель общих функций и отправки методов.
– Joshua Ulrich
27 December 2017 в 22:48
RStudio
, он попытается вытащить источник для функции вашего текстового курсора, если вы нажмете клавишуF2
. – Ari B. Friedman 26 October 2013 в 20:37scale
, который есть S3 - я получилUseMethod("scale")
, а затем использовалgetAnywhere(scale.default)
). Но простые функции работают нормально. – Tomasz Gandor 12 May 2017 в 08:36