Проще и, скорее всего, быстрее, чем указано выше, для списков любых нерекурсивных (в смысле is.recursive
) значений:
example_1_LST <- list(NULL, a=1.0, b=Matrix::Matrix(), c=NULL, d=4L)
example_2_LST <- as.list(unlist(example_1_LST, recursive=FALSE))
str(example_2_LST)
печатает:
List of 3
$ a: num 1
$ b:Formal class 'lsyMatrix' [package "Matrix"] with 5 slots
.. ..@ x : logi NA
.. ..@ Dim : int [1:2] 1 1
.. ..@ Dimnames:List of 2
.. .. ..$ : NULL
.. .. ..$ : NULL
.. ..@ uplo : chr "U"
.. ..@ factors : list()
$ d: int 4
Использование JSONPath было бы одним из самых гибких решений, если вы захотите включить библиотеку: https://github.com/s3u/JSONPath (узел и браузер)
Для вашего случая использования путь json будет:
$..items[1].name
, поэтому:
var secondName = jsonPath.eval(data, "$..items[1].name");
Если вы ищете один или несколько объектов, которые соответствуют определенным критериям, у вас есть несколько вариантов с помощью query-js
//will return all elements with an id larger than 1
data.items.where(function(e){return e.id > 1;});
//will return the first element with an id larger than 1
data.items.first(function(e){return e.id > 1;});
//will return the first element with an id larger than 1
//or the second argument if non are found
data.items.first(function(e){return e.id > 1;},{id:-1,name:""});
Также есть single
и singleOrDefault
они работают так же, как first
и firstOrDefault
соответственно. Единственное отличие состоит в том, что они будут бросать, если больше , чем найдено одно совпадение.
для дальнейшего объяснения query-js вы можете начать с этой почты
Иногда доступ к вложенному объекту с использованием строки может быть желательным. Простым подходом является первый уровень, например
var obj = { hello: "world" };
var key = "hello";
alert(obj[key]);//world
. Но это часто бывает не со сложным json. По мере усложнения json подходы к определению значений внутри json также становятся сложными. Рекурсивный подход для навигации по json лучше всего, и то, как эта рекурсия используется, будет зависеть от типа поиска данных. Если имеются условные операторы, поиск json может быть хорошим инструментом для использования.
Если доступное свойство уже известно, но путь является сложным, например, в этот объект
var obj = {
arr: [
{ id: 1, name: "larry" },
{ id: 2, name: "curly" },
{ id: 3, name: "moe" }
]
};
И вы знаете, что хотите получить первый результат массива в объекте, возможно, вы хотели бы использовать
var moe = obj["arr[0].name"];
. Однако это приведет к исключение, поскольку нет свойства объекта с этим именем. Решение, чтобы иметь возможность использовать это, было бы сгладить аспект дерева объекта. Это можно сделать рекурсивно.
function flatten(obj){
var root = {};
(function tree(obj, index){
var suffix = toString.call(obj) == "[object Array]" ? "]" : "";
for(var key in obj){
if(!obj.hasOwnProperty(key))continue;
root[index+key+suffix] = obj[key];
if( toString.call(obj[key]) == "[object Array]" )tree(obj[key],index+key+suffix+"[");
if( toString.call(obj[key]) == "[object Object]" )tree(obj[key],index+key+suffix+".");
}
})(obj,"");
return root;
}
Теперь сложный объект может быть сплющен
var obj = previous definition;
var flat = flatten(obj);
var moe = flat["arr[0].name"];//moe
Вот jsFiddle Demo
этого подхода.
obj["arr[0].name"]
вместо obj.arr[0].name
? Вам вряд ли нужно / нужно иметь дело с сплющенными объектами , за исключением сериализации.
– Bergi
19 August 2014 в 17:00
Я не думаю, что вопросник касается только одного вложенного объекта уровня, поэтому я представляю следующую демонстрацию, чтобы продемонстрировать, как получить доступ к узлу глубоко вложенного объекта json. Хорошо, давайте найдем узел с идентификатором '5'.
var data = {
code: 42,
items: [{
id: 1,
name: 'aaa',
items: [{
id: 3,
name: 'ccc'
}, {
id: 4,
name: 'ddd'
}]
}, {
id: 2,
name: 'bbb',
items: [{
id: 5,
name: 'eee'
}, {
id: 6,
name: 'fff'
}]
}]
};
var jsonloop = new JSONLoop(data, 'id', 'items');
jsonloop.findNodeById(data, 5, function(err, node) {
if (err) {
document.write(err);
} else {
document.write(JSON.stringify(node, null, 2));
}
});
<script src="https://rawgit.com/dabeng/JSON-Loop/master/JSONLoop.js"></script>
На всякий случай, кто-то посещает этот вопрос в 2017 году или позже и ищет легкий для запоминания способ, вот подробное сообщение в блоге по Доступ к вложенным объектам в JavaScript без бамбука с помощью
Невозможно прочитать свойство «foo» неопределенной ошибки
Самый простой и самый чистый способ - использовать шаблон доступа к вложенным объектам Oliver Steele
const name = ((user || {}).personalInfo || {}).name;
. В этих обозначениях вы никогда не столкнетесь с
Невозможно прочитать свойство 'name' неопределенного .
Вы в основном проверяете, существует ли пользователь, если нет, вы создаете пустой объект «на лету». Таким образом, ключ следующего уровня будет всегда доступен из объекта, который существует, или пустого объекта, но никогда из неопределенного.
Чтобы иметь доступ к вложенным массивам, вы можете написать собственный массив, уменьшающий использование.
const getNestedObject = (nestedObj, pathArr) => {
return pathArr.reduce((obj, key) =>
(obj && obj[key] !== 'undefined') ? obj[key] : undefined, nestedObj);
}
// pass in your object structure as array elements
const name = getNestedObject(user, ['personalInfo', 'name']);
// to access nested array, just pass in array index as an element the path array.
const city = getNestedObject(user, ['personalInfo', 'addresses', 0, 'city']);
// this will return the city from the first address item.
Существует также отличная библиотека обработки минимального типа typy , который делает все это для вас.
((user || {}).address || new Array(3))[1].name
– Dinesh Pandiyan
8 July 2018 в 16:20
...[1].bar
приведет к ошибке, если элемент 1
не существует. Но это также относится к ....foo.bar
, если foo
не существует. Вам нужно «охранять». также доступ к 1
, так же, как и вы "guard" любой другой доступ к собственности. Массив - это всего лишь объект. Элемент "массив" это просто свойство. Правильно оно было бы (((user || {}).address || {})[1] || {}).name
.
– Felix Kling
9 July 2018 в 03:49
Чтобы получить доступ к вложенному атрибуту, вам нужно указать его имя, а затем выполнить поиск по объекту.
Если вы уже знаете точный путь, вы можете записать его в своем скрипте так:
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.
Доступ к динамически многоуровневому объекту.
var obj = {
name: "salut",
subobj: {
subsubobj: {
names: "I am sub sub obj"
}
}
};
var level = "subobj.subsubobj.names";
level = level.split(".");
var currentObjState = obj;
for (var i = 0; i < level.length; i++) {
currentObjState = currentObjState[level[i]];
}
console.log(currentObjState);
Рабочая скрипка: https://jsfiddle.net/andreitodorut/3mws3kjL/
Этот вопрос довольно старый, так как современное обновление. С наступлением ES2015 есть альтернативы для получения требуемых данных. В настоящее время существует функция, называемая деструктурированием объекта для доступа к вложенным объектам.
const data = {
code: 42,
items: [{
id: 1,
name: 'foo'
}, {
id: 2,
name: 'bar'
}]
};
const {
items: [, {
name: secondName
}]
} = data;
console.log(secondName);
В приведенном выше примере создается переменная, называемая secondName
из name
из массива с именем items
, одиночный ,
говорит пропустить первый объект в массиве.
Примечательно, что это, вероятно, слишком велико для этого примера, так как простой доступ к массиву легче читать, но он пригодится при разрыве объектов вообще.
Это очень краткое введение в ваш конкретный вариант использования, деструктурирование может быть необычным синтаксисом, чтобы привыкнуть к нему сначала. Я бы порекомендовал прочитать документацию по присваиванию демаркации Mozilla , чтобы узнать больше.
Вы можете использовать функцию lodash _get
:
var object = { 'a': [{ 'b': { 'c': 3 } }] };
_.get(object, 'a[0].b.c');
// => 3
Если вы пытаетесь получить доступ к item
из структуры примера с помощью id
или name
, не зная его позиции в массиве, самый простой способ сделать это - использовать подчеркивание .js :
var data = {
code: 42,
items: [{
id: 1,
name: 'foo'
}, {
id: 2,
name: 'bar'
}]
};
_.find(data.items, function(item) {
return item.id === 2;
});
// Object {id: 2, name: "bar"}
По моему опыту, использование функций более высокого порядка вместо for
или for..in
циклов приводит к тому, что код легче прояснить и, следовательно, более удобен в обслуживании .
Только мои 2 цента.
Использование lodash было бы хорошим решением
Пример:
var object = { 'a': { 'b': { 'c': 3 } } };
_.get(object, 'a.b.c');
// => 3
Объекты и массивы имеют множество встроенных методов, которые могут помочь вам в обработке данных.
Примечание: во многих примерах я использую функции arrow . Они аналогичны выражениям функции , но они связывают значение this
лексически.
Object.keys()
, Object.values()
(ES 2017) и Object.entries()
(ES 2017) Object.keys()
возвращает массив ключей объекта, Object.values()
возвращает массив значений объекта, а Object.entries()
возвращает массив ключей объекта и соответствующие значения в формате [key, value]
.
const obj = {
a: 1
,b: 2
,c: 3
}
console.log(Object.keys(obj)) // ['a', 'b', 'c']
console.log(Object.values(obj)) // [1, 2, 3]
console.log(Object.entries(obj)) // [['a', 1], ['b', 2], ['c', 3]]
Object.entries()
с (g15) const obj = {
a: 1
,b: 2
,c: 3
}
for (const [key, value] of Object.entries(obj)) {
console.log(`key: ${key}, value: ${value}`)
}
Очень удобно повторять результат Object.entries()
с для цикла и .
Цикл for-loop позволяет выполнять итерацию элементов массива. Синтаксис for (const element of array)
(мы можем заменить const
на var
или let
, но лучше использовать const
, если мы не намерены изменять element
).
Назначение destructuring позволяет извлекать значения из массива или объекта и назначать их переменным. В этом случае const [key, value]
означает, что вместо назначения массива [key, value]
на element
мы назначим первый элемент этого массива key
, а второй - value
. Это эквивалентно этому:
for (const element of Object.entries(obj)) {
const key = element[0]
,value = element[1]
}
Как вы можете видеть, деструктуризация делает это намного проще.
Array.prototype.every()
и Array.prototype.some()
Метод every()
возвращает true
, если указанная функция обратного вызова возвращает true
для каждого элемента массива. Метод some()
возвращает true
, если указанная функция обратного вызова возвращает true
для некоторого (хотя бы одного) элемента.
const arr = [1, 2, 3]
// true, because every element is greater than 0
console.log(arr.every(x => x > 0))
// false, because 3^2 is greater than 5
console.log(arr.every(x => Math.pow(x, 2) < 5))
// true, because 2 is even (the remainder from dividing by 2 is 0)
console.log(arr.some(x => x % 2 === 0))
// false, because none of the elements is equal to 5
console.log(arr.some(x => x === 5))
Array.prototype.find()
и Array.prototype.filter()
Методы find()
возвращают первый ], который удовлетворяет предоставленной функции обратного вызова. Метод filter()
возвращает массив из всех элементов, который удовлетворяет предоставленной функции обратного вызова.
const arr = [1, 2, 3]
// 2, because 2^2 !== 2
console.log(arr.find(x => x !== Math.pow(x, 2)))
// 1, because it's the first element
console.log(arr.find(x => true))
// undefined, because none of the elements equals 7
console.log(arr.find(x => x === 7))
// [2, 3], because these elements are greater than 1
console.log(arr.filter(x => x > 1))
// [1, 2, 3], because the function returns true for all elements
console.log(arr.filter(x => true))
// [], because none of the elements equals neither 6 nor 7
console.log(arr.filter(x => x === 6 || x === 7))
Array.prototype.map()
Метод map()
возвращает массив с результатами вызова предоставленной функции обратного вызова для элементов массива.
const arr = [1, 2, 3]
console.log(arr.map(x => x + 1)) // [2, 3, 4]
console.log(arr.map(x => String.fromCharCode(96 + x))) // ['a', 'b', 'c']
console.log(arr.map(x => x)) // [1, 2, 3] (no-op)
console.log(arr.map(x => Math.pow(x, 2))) // [1, 4, 9]
console.log(arr.map(String)) // ['1', '2', '3']
] Array.prototype.reduce()
Метод reduce()
уменьшает массив до одного значения, вызывая предоставленную функцию обратного вызова с двумя элементами .
const arr = [1, 2, 3]
// Sum of array elements.
console.log(arr.reduce((a, b) => a + b)) // 6
// The largest number in the array.
console.log(arr.reduce((a, b) => a > b ? a : b)) // 3
Метод reduce()
принимает необязательный второй параметр, который является начальным значением. Это полезно, когда массив, на который вы вызываете reduce()
, может иметь нуль или один элемент. Например, если бы мы хотели создать функцию sum()
, которая принимает массив в качестве аргумента и возвращает сумму всех элементов, мы могли бы написать это следующим образом:
const sum = arr => arr.reduce((a, b) => a + b, 0)
console.log(sum([])) // 0
console.log(sum([4])) // 4
console.log(sum([2, 5])) // 7
Которая является библиотекой JavaScript, которая предоставляет целый беспорядок полезных помощников functional programming
без расширения каких-либо встроенных объектов.
var data = {
code: 42,
items: [{
id: 1,
name: 'foo'
}, {
id: 2,
name: 'bar'
}]
};
var item = _.findWhere(data.items, {
id: 2
});
if (!_.isUndefined(item)) {
console.log('NAME =>', item.name);
}
//using find -
var item = _.find(data.items, function(item) {
return item.id === 2;
});
if (!_.isUndefined(item)) {
console.log('NAME =>', item.name);
}
Пифонический, рекурсивный и функциональный подход к разгадке произвольных деревьев JSON:
handlers = {
list: iterate,
dict: delve,
str: emit_li,
float: emit_li,
}
def emit_li(stuff, strong=False):
emission = '<li><strong>%s</strong></li>' if strong else '<li>%s</li>'
print(emission % stuff)
def iterate(a_list):
print('<ul>')
map(unravel, a_list)
print('</ul>')
def delve(a_dict):
print('<ul>')
for key, value in a_dict.items():
emit_li(key, strong=True)
unravel(value)
print('</ul>')
def unravel(structure):
h = handlers[type(structure)]
return h(structure)
unravel(data)
, где data - список python (проанализирован из текстовой строки JSON):
data = [
{'data': {'customKey1': 'customValue1',
'customKey2': {'customSubKey1': {'customSubSubKey1': 'keyvalue'}}},
'geometry': {'location': {'lat': 37.3860517, 'lng': -122.0838511},
'viewport': {'northeast': {'lat': 37.4508789,
'lng': -122.0446721},
'southwest': {'lat': 37.3567599,
'lng': -122.1178619}}},
'name': 'Mountain View',
'scope': 'GOOGLE',
'types': ['locality', 'political']}
]
Я предпочитаю JQuery. Это чище и легко читается.
$.each($.parseJSON(data), function (key, value) {
alert(value.<propertyname>);
});
Функция grep jQuery позволяет фильтровать через массив:
var data = {
code: 42,
items: [{
id: 1,
name: 'foo'
}, {
id: 2,
name: 'bar'
}]
};
$.grep(data.items, function(item) {
if (item.id === 2) {
console.log(item.id); //console id of item
console.log(item.name); //console name of item
console.log(item); //console item object
return item; //returns item object
}
});
// Object {id: 2, name: "bar"}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Старый вопрос, но поскольку никто не упоминал lodash (просто подчеркивание).
Если вы уже используете lodash в своем проекте, я думаю, что это элегантный способ сделать это в сложном примере:
Опция 1
_.get(response, ['output', 'fund', 'data', '0', 'children', '0', 'group', 'myValue'], '')
такая же, как:
Opt 2
response.output.fund.data[0].children[0].group.myValue
Разница между первой и второй опцией заключается в том, что в Opt 1, если у вас есть одно из свойств, которые отсутствуют (undefined) в пути, в котором вы не получили ошибку, он возвращает вам третий параметр.
Для фильтра массива lodash есть _.find()
, но я бы предпочел используйте обычный filter()
. Но я все же считаю, что вышеупомянутый метод _.get()
очень полезен при работе с действительно сложными данными.
Я надеюсь, что это может быть полезно для тех, кто ищет варианты для обработки действительно сложных данных, которые подразумевает название.
Вы можете получить к нему доступ таким образом
data.items[1].name
или
data["items"][1]["name"]
Оба способа равны.