Как получить свойства нижнего уровня из массива объектов внутри другого массива объектов в JavaScript

<!DOCTYPE html>
<html>
<head>
<meta charset = "UTF-8">
<title>VR train search</title>
<!-- 
Data provided by https://www.digitraffic.fi/, used under the following license:
Creative Commons Attribution 4.0 International (CC BY 4.0)

Search for train connections through the VR API
https://www.digitraffic.fi/rautatieliikenne/#reittiperusteinen-haku

 -->
</head>

<body>
	<h3>Train search</h3>

	<form>
		<p>Ignore the search fields, I have hard-coded the stations in this example to make the code shorter. Just click Search trains.</p>
		<label>From:</label> 
		<input type = "text" id = "departure_station">
		<label>To:</label> 
		<input type = "text" id = "arrival_station">
		<label>Date (yyyy-mm-dd):</label> 
		<input type = "text" id = "departure_date">
		<input type = "button" value = "Search trains" onclick = "searchTrains()">
	</form>

	<div id = "onscreen_text"></div>

	<script type = "text/javascript">

	function searchTrains() {

		var departure_station = "HKI";
		var arrival_station = "TPE";
		var departure_date = "2019-02-12";
	
		var xmlhttp = new XMLHttpRequest();
		var json;
			
		xmlhttp.onreadystatechange = function() {

			if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
				json = xmlhttp.responseText;
				listResults(json);
			}
			
			if (xmlhttp.readyState == 4 && xmlhttp.status == 404) {
				document.getElementById("onscreen_text").innerHTML = "<p>No search results found in the VR API.</p>";
			}
		}
		// Get the data from the API
		xmlhttp.open(
			"GET", "https://rata.digitraffic.fi/api/v1/live-trains/station/" + departure_station + "/" + arrival_station + "?" + "departure_date = " + departure_date + "&limit=10", true);
		xmlhttp.send();
	}
	
	function listResults(json) {

		var results = JSON.parse(json);
		console.info(results); // testing
		var text = ""; // testing

		// filter results for only passenger trains
		var passengerTrains = [];
		function getPassengerTrains() {
			for (var i = 0; i < results.length; i++) {
				if (results[i].trainCategory == "Long-distance" || results[i].trainCategory == "Commuter") {
					passengerTrains.push(results[i]);
					text = text + results[i].trainNumber + "<br>"; // testing
				}
			}
		}
		getPassengerTrains();
		console.info(passengerTrains); // testing
		
		// Get the desired properties from the filtered trains
		// https://stackoverflow.com/questions/37750309/find-object-by-property-in-an-array-of-javascript-objects-inside-another-array
		
		var station = passengerTrains.map(item => item.timeTableRows.stationShortCode);
		console.info(station); // but this returns an array full of undefined
		
		// Loop through array of train objects
		for (var i = 0; i < passengerTrains.length; i++) {
			console.info(passengerTrains[i]); // this seems to give the right result
			// Loop through each train object to get timeTableRows subarray
			for (var train in passengerTrains[i]) {
				// make a new array named timetable
				var timetable = passengerTrains[i].timeTableRows;
				console.info(timetable);
				// but this prints the same array 13 times = as many times as there are properties in the train object
				/*	Commented out because it freezes my browser	
				// Loop through each object in the timetable subarray to get the desired properties
				for (var j=0; j < timetable.length; j++) {
					console.info(timetable[j]);
					for (var row in timetable[j]) {
						text = text + "<p>From/to: " + timetable[j].stationShortCode;
						text = text + "<br>Time: " + timetable[j].scheduledTime;
						text = text + "<br>Train stopping: " + timetable[j].trainStopping;
						text = text + "<br>Departure/arrival: " + timetable[j].type + "</p>"; 
					} 
				} */
			} 
		document.getElementById("onscreen_text").innerHTML = text;
		}
	}

	</script>
</body>
</html>

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

Я работаю с проанализированным JSON-файлом расписания поездов типа, возвращаемого этим общедоступным API: https://rata.digitraffic.fi/api/v1/live-trains/station/HKI/TPE?departure_date=2019-02-12

Проанализированный результат представляет собой массив объектов поезда с подмассивом с именем timeTableRows, полным объектов со свойствами, такими как stationShortCode: «HKI», запланированное время: «2019-02-12T05:04:00.000Z» и т. д. Я хочу добраться до этих свойства нижнего уровня. Скрин из консоли для ясности

Я попробовал ответ, данный здесь: Найти объект по свойству в массиве объектов JavaScript внутри другого массива

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

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

js snippet removed

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

messerbill 11.02.2019 16:10

Пожалуйста, редактировать ваш вопрос, чтобы включить пример данных, которые вы ищете. Не все могут получить доступ к сайту, если они находятся за брандмауэрами и т. д. Вы можете включить его в свой фрагмент, чтобы нажатие «Выполнить фрагмент кода» приводило к чему-то другому, кроме ошибки :).

Heretic Monkey 11.02.2019 16:24

Спасибо, я преобразовал пример в полноценный HTML-файл, чтобы он запускался и выдавал данные в консоли. По какой-то причине здесь он работает очень медленно, но нет проблем, если я запускаю его прямо из Блокнота в Firefox. Скриншот в моем посте также показывает структуру массива с данными, которые я ищу на нижнем уровне (stationShortCode и т.д.).

ssilvonen 12.02.2019 09:18
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
3
208
3

Ответы 3

Вы можете использовать Ramda для этого, https://ramdajs.com/docs/#путь. Это даст вам значение желаемого свойства, введя путь, чтобы вы могли использовать его следующим образом:

R.map(train => {
    train_id:train.trainNumber,
    timeTableRows:R.path(["path","to","property"],train)
}, trains)
function fetchNestedObject(prop, obj) {
    let keys = prop.split('.');
    keys[0] = obj[keys[0]];
    return keys.reduce((a, b) => a && a[b]);
}

Использование:

fetchNestedObject('v.a.d.0', {v: {a: {d: [1]}}})

Спасибо за ответы выше, я отмечу их для дальнейшего использования, хотя они слишком продвинуты для моего текущего уровня знаний JS. Прямо сейчас мне удалось создать серию вложенных циклов for, которые, кажется, делают то, что я хочу, но я буду рад получить дальнейшие комментарии или улучшения по этому решению.

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

        // passengerTrains is the top-level array
        for (var i = 0; i < passengerTrains.length; i++) {
            var train = passengerTrains[i]; // each train is an object
            //console.info(train);
            var trainNumber = train.trainNumber;
            //console.info(trainNumber);
            // Loop through array of timeTableRows inside each train object
            for (var j = 0; j < train.timeTableRows.length; j++) {
                var row = train.timeTableRows[j]; // each row is an object
                // console.info(row);
                // Print out only the data that we want
                // The variables dep and arr are defined elsewhere in the code
                if (row.stationShortCode == dep && row.type == "DEPARTURE") {
                    text = text + "Train " + trainNumber + ": Departure from " + departure_station + " at " + row.scheduledTime + "<br>";
                    console.info("Train " + trainNumber + ": Departure from " + departure_station + " at " + row.scheduledTime);
                }
                if (row.stationShortCode == arr && row.type == "ARRIVAL") {
                    text = text + "Train " + trainNumber + ": Arrival at " + arrival_station + " at " + row.scheduledTime + "<br><br>";
                    console.info("Train " + trainNumber + ": Arrival at " + arrival_station + " at " + row.scheduledTime);
                }
            }
        document.getElementById("onscreen_text").innerHTML = text;
        }

Другие вопросы по теме