Чтобы получить доступ к вложенному атрибуту, вам нужно указать его имя, а затем выполнить поиск по объекту.
Если вы уже знаете точный путь, вы можете записать его в своем скрипте так:
data['items'][1]['name']
, они также работают -
data.items[1].name
data['items'][1].name
data.items[1]['name']
Когда вы не знаете точное имя перед рукой, или пользователь, который предоставляет вам имя. Затем требуется динамический поиск по структуре данных. Некоторые предположили, что поиск может быть выполнен с использованием петли for
, но есть очень простой способ пройти путь, используя Array.reduce
.
const data = { code: 42, items: [{ id: 1, name: 'foo' }, { id: 2, name: 'bar' }] }
const path = [ 'items', '1', 'name']
let result = path.reduce((a,v) => a[v], data)
путь - это способ сказать: сначала возьмите объект с ключом items
, который оказывается массивом. Затем возьмите элемент 1
-st (0 индексных массивов). Последний возьмет объект с ключом name
в этом элементе массива, который является строкой bar
.
Если у вас очень длинный путь, вы можете даже использовать String.split
, чтобы сделать все это проще -
'items.1.name'.split('.').reduce((a,v) => a[v], data)
Это простой JavaScript, без использования каких-либо сторонних библиотек, таких как jQuery или lodash.
Попробуйте:
DT = data.table(col1 = 1:3)
colname = "col1"
DT[, colname, with = FALSE] # select
# col1
# 1: 1
# 2: 2
# 3: 3
DT[, (colname) := 4:6] # assign
# col1
# 1: 4
# 2: 5
# 3: 6
Последний известен как столбец plonk , потому что вы заменяете весь вектор столбца ссылкой. Если подмножество i
присутствует, оно будет переназначать по ссылке. Параны вокруг (colname)
- это стенография, представленная в версии v1.9.4 на CRAN Oct 2014. Вот новость:
Using `with = FALSE` with `:=` is now deprecated in all cases, given that wrapping
the LHS of `:=` with parentheses has been preferred for some time.
colVar = "col1"
DT[, colVar := 1, with = FALSE] # deprecated, still works silently
DT[, (colVar) := 1] # please change to this
DT[, c("col1", "col2") := 1] # no change
DT[, 2:4 := 1] # no change
DT[, c("col1","col2") := list(sum(a), mean(b)] # no change
DT[, `:=`(...), by = ...] # no change
См. Также раздел «Подробности» в ?`:=`
:
DT[i, (colnamevector) := value]
# [...] The parens are enough to stop the LHS being a symbol
И чтобы ответить на дальнейший вопрос в комментарии, вот один из способов (как обычно, существует много способов):
DT[, colname := cumsum(get(colname)), with = FALSE]
# col1
# 1: 4
# 2: 9
# 3: 15
или вам может быть проще читать, писать и отлаживать только до eval
a paste
, аналогично построению динамического оператора SQL для отправки на сервер:
expr = paste0("DT[,",colname,":=cumsum(",colname,")]")
expr
# [1] "DT[,col1:=cumsum(col1)]"
eval(parse(text=expr))
# col1
# 1: 4
# 2: 13
# 3: 28
Если вы делаете это много, вы можете определить вспомогательную функцию EVAL
:
EVAL = function(...)eval(parse(text=paste0(...)),envir=parent.frame(2))
EVAL("DT[,",colname,":=cumsum(",colname,")]")
# col1
# 1: 4
# 2: 17
# 3: 45
Теперь, когда data.table
1.8.2 автоматически оптимизирует j
для эффективности, может быть предпочтительнее использовать метод eval
. get()
в j
предотвращает некоторые оптимизации, например.
Или существует set()
. Низкая накладная, функциональная форма :=
, которая была бы прекрасна здесь. См. ?set
.
set(DT, j = colname, value = cumsum(DT[[colname]]))
DT
# col1
# 1: 4
# 2: 21
# 3: 66
* Это не ответ на самом деле, но у меня нет достаточного количества уличных отзывов для комментариев: /
В любом случае, для тех, кто может попытаться создать новый столбец в таблице данных с именем, хранящимся в переменной, у меня есть следующее, чтобы работать. Я понятия не имею, что это за производительность. Любые предложения по улучшению? Можно ли предположить, что безымянный новый столбец всегда будет иметь имя V1?
colname <- as.name("users")
# Google Analytics query is run with chosen metric and resulting data is assigned to DT
DT2 <- DT[, sum(eval(colname, .SD)), by = country]
setnames(DT2, "V1", as.character(colname))
Обратите внимание, что я могу ссылаться на него как раз в сумме (), но, похоже, не может его назначить в тот же шаг. BTW, причина, по которой мне нужно это сделать, это colname будет основываться на пользовательском входе в приложение Shiny.
Для нескольких столбцов и функции, применяемой к значениям столбца.
При обновлении значений из функции RHS должен быть объектом списка, поэтому использование цикла на .SD
с lapply
сделает трюк.
Пример ниже конвертирует целочисленные столбцы в числовые столбцы
a1 <- data.table(a=1:5, b=6:10, c1=letters[1:5])
sapply(a1, class) # show classes of columns
# a b c1
# "integer" "integer" "character"
# column name character vector
nm <- c("a", "b")
# Convert columns a and b to numeric type
a1[, j = (nm) := lapply(.SD, as.numeric ), .SDcols = nm ]
sapply(a1, class)
# a b c1
# "numeric" "numeric" "character"