массив разбора в объекте json [duplicate]

Проще и, скорее всего, быстрее, чем указано выше, для списков любых нерекурсивных (в смысле 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
667
задан AndrewL 24 May 2018 в 22:22
поделиться

20 ответов

883
ответ дан 25 revs, 6 users 92% 15 August 2018 в 20:24
поделиться

Использование JSONPath было бы одним из самых гибких решений, если вы захотите включить библиотеку: https://github.com/s3u/JSONPath (узел и браузер)

Для вашего случая использования путь json будет:

$..items[1].name

, поэтому:

var secondName = jsonPath.eval(data, "$..items[1].name");
6
ответ дан Andrejs 15 August 2018 в 20:24
поделиться
  • 1
    Использование eval () не является хорошим решением. Вместо этого можно использовать функцию первого класса. – pradeep gowda 27 September 2017 в 12:18

Если вы ищете один или несколько объектов, которые соответствуют определенным критериям, у вас есть несколько вариантов с помощью 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 вы можете начать с этой почты

3
ответ дан Bergi 15 August 2018 в 20:24
поделиться
  • 1
    Мне было бы интересно узнать, как это можно улучшить. Оставить комментарий? – Rune FS 18 June 2015 в 18:42

Иногда доступ к вложенному объекту с использованием строки может быть желательным. Простым подходом является первый уровень, например

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 этого подхода.

15
ответ дан Community 15 August 2018 в 20:24
поделиться
  • 1
    WTH вы бы хотели использовать obj["arr[0].name"] вместо obj.arr[0].name? Вам вряд ли нужно / нужно иметь дело с сплющенными объектами , за исключением сериализации. – Bergi 19 August 2014 в 17:00
  • 2
    @Bergi - Обычно я рассматриваю этот вопрос, и поскольку это используется канонически, я отправил ответ на эту версию. Если этого избежать, гораздо проще использовать obj.arr [0] .name, но иногда люди хотят передать аксессуры строк, и это пример этого. – Travis J 19 August 2014 в 18:28
  • 3
    Urgh. Тем не менее, вряд ли есть причина сгладить полный объект только для использования одного строкового пути, вы можете просто проанализировать его и выполнить динамический поиск. – Bergi 19 August 2014 в 18:29

Я не думаю, что вопросник касается только одного вложенного объекта уровня, поэтому я представляю следующую демонстрацию, чтобы продемонстрировать, как получить доступ к узлу глубоко вложенного объекта 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>

1
ответ дан dabeng 15 August 2018 в 20:24
поделиться
  • 1
    Как получить доступ к вложенному объекту json с помощью переменных. data = {a: {b: 'ss'}}; var key = a.b data [key] не работает – Pasupathi Rajamanickam 14 November 2017 в 21:51

На всякий случай, кто-то посещает этот вопрос в 2017 году или позже и ищет легкий для запоминания способ, вот подробное сообщение в блоге по Доступ к вложенным объектам в JavaScript без бамбука с помощью

Невозможно прочитать свойство «foo» неопределенной ошибки

1. Схема доступа вложенных объектов Oliver Steele

Самый простой и самый чистый способ - использовать шаблон доступа к вложенным объектам Oliver Steele

const name = ((user || {}).personalInfo || {}).name;

. В этих обозначениях вы никогда не столкнетесь с

Невозможно прочитать свойство 'name' неопределенного .

Вы в основном проверяете, существует ли пользователь, если нет, вы создаете пустой объект «на лету». Таким образом, ключ следующего уровня будет всегда доступен из объекта, который существует, или пустого объекта, но никогда из неопределенного.

2. Доступ к вложенным объектам с использованием массива Уменьшить

Чтобы иметь доступ к вложенным массивам, вы можете написать собственный массив, уменьшающий использование.

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 , который делает все это для вас.

0
ответ дан Dinesh Pandiyan 15 August 2018 в 20:24
поделиться
  • 1
    Этот вопрос в основном касается доступных свойств доступа. Существует уже вопрос о том, что вы имеете в виду (и уже включили большинство ваших решений): Безопасно вставлять Javascript-объекты в или Доступ к вложенным объектам JavaScript со строковым ключом . Но в любом случае: & quot; К сожалению, вы не можете получить доступ к вложенным массивам с помощью этого трюка. & Quot; Почему бы и нет? Массивы - это объекты, поэтому они должны работать так же хорошо. Можете ли вы привести пример, где это не так? – Felix Kling 7 July 2018 в 15:47
  • 2
    @FelixKling Когда мы пытаемся получить доступ к массивам с помощью шаблона Оливера Стила, мы не сможем создать массив на «n» на лету и получить доступ к n-му индексу без получения ошибки «undefined». Ex. ((user || {}).address || new Array(3))[1].name – Dinesh Pandiyan 8 July 2018 в 16:20
  • 3
    Вы не применяете свой шаблон последовательно. Конечно, ...[1].bar приведет к ошибке, если элемент 1 не существует. Но это также относится к ....foo.bar, если foo не существует. Вам нужно «охранять». также доступ к 1, так же, как и вы "guard" любой другой доступ к собственности. Массив - это всего лишь объект. Элемент "массив" это просто свойство. Правильно оно было бы (((user || {}).address || {})[1] || {}).name. – Felix Kling 9 July 2018 в 03:49
  • 4
    Отлично. Мне это не удавалось. Спасибо @FelixKling, я буду обновлять сообщения в блогах. – Dinesh Pandiyan 9 July 2018 в 04:01
  • 5
    – reggaeguitar 27 September 2018 в 18:03

Чтобы получить доступ к вложенному атрибуту, вам нужно указать его имя, а затем выполнить поиск по объекту.

Если вы уже знаете точный путь, вы можете записать его в своем скрипте так:

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.

3
ответ дан Evgeny 15 August 2018 в 20:24
поделиться

Доступ к динамически многоуровневому объекту.

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/

1
ответ дан Ilyas karim 15 August 2018 в 20:24
поделиться

Этот вопрос довольно старый, так как современное обновление. С наступлением 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 , чтобы узнать больше.

8
ответ дан Jon Chesterfield 15 August 2018 в 20:24
поделиться

Вы можете использовать функцию lodash _get:

var object = { 'a': [{ 'b': { 'c': 3 } }] };

_.get(object, 'a[0].b.c');
// => 3
3
ответ дан Koby Douek 15 August 2018 в 20:24
поделиться

Если вы пытаетесь получить доступ к 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 цента.

22
ответ дан lukas.pukenis 15 August 2018 в 20:24
поделиться

Использование lodash было бы хорошим решением

Пример:

var object = { 'a': { 'b': { 'c': 3 } } };                                                                                               
_.get(object, 'a.b.c');                                                                                             
// => 3  
-1
ответ дан Machavity 15 August 2018 в 20:24
поделиться

Объекты и массивы имеют множество встроенных методов, которые могут помочь вам в обработке данных.

Примечание: во многих примерах я использую функции 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

11
ответ дан Michał Perłakowski 15 August 2018 в 20:24
поделиться

Underscore js Way

Которая является библиотекой 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);
}
2
ответ дан Mohan Dere 15 August 2018 в 20:24
поделиться

Пифонический, рекурсивный и функциональный подход к разгадке произвольных деревьев 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']}
]
0
ответ дан pX0r 15 August 2018 в 20:24
поделиться
  • 1
    Этот вопрос касается JavaScript, а не Python. Не уверен, есть ли эквивалентный вопрос для Python. – Felix Kling 28 December 2016 в 20:54
  • 2
    Lo, спасибо за ваш ответ Python на JavaScript Вопрос – Ilyas karim 27 March 2018 в 19:46
  • 3
    Жесткая толпа, здесь. – pX0r 19 July 2018 в 07:05

Я предпочитаю JQuery. Это чище и легко читается.

 $.each($.parseJSON(data), function (key, value) {
    alert(value.<propertyname>);
});

4
ответ дан Rudy Hinojosa 15 August 2018 в 20:24
поделиться

Функция 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>

1
ответ дан user 15 August 2018 в 20:24
поделиться

Старый вопрос, но поскольку никто не упоминал 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() очень полезен при работе с действительно сложными данными.

Я надеюсь, что это может быть полезно для тех, кто ищет варианты для обработки действительно сложных данных, которые подразумевает название.

1
ответ дан Ventura 15 August 2018 в 20:24
поделиться

Вы можете получить к нему доступ таким образом

data.items[1].name

или

data["items"][1]["name"]

Оба способа равны.

48
ответ дан vitmalina 15 August 2018 в 20:24
поделиться
  • 1
    Да, но вы не можете делать данные [& quot; items & quot;]. 1.name – neaumusic 21 October 2015 в 19:01
  • 2
    Во-первых, это гораздо более интуитивно понятный, читаемый и более короткий;) Я предпочитаю использовать синтаксис свойства скобки только тогда, когда имя свойства является переменным. – DanteTheSmith 2 October 2017 в 11:59
-1
ответ дан Riddick 5 September 2018 в 19:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: