l oop через массив json с javascript - PullRequest
0 голосов
/ 01 мая 2020

У меня проблема с циклом json -Array с javascript в nodejs. мой массив под названием birthdaysArray выглядит следующим образом:

[{"birth":"23.04.1988","name":"Tom Smith"},{"birth":"15.04.2010","name":"Mini Jall"},...,{"birth":"23.04.2001","name":"Michael Bird"},{"birth":"15.11.1999","name":"Frank Middleton"}]

теперь я хочу иметь массив, в котором перечислены дни рождения (отсортированные по дню рождения) текущего месяца. Записи с одинаковым днем ​​и месяцем (например, 23.04) должны быть указаны в одну и ту же дату. это должно выглядеть так: , если апрель - это текущий месяц (в списке более 100 записей.):

[{"day":"15","name":["Mini Jall"]},{"day":"23", "name": ["Tom Smith","Michael Bird"]}]

я оглянулся, но я не не найти решение для этого. я проверил это:

for(var i = 0; i < json.length; i++) {
    var obj = json[i];
    console.log(obj.id);
}

но не соответствовало. Кто может помочь?

вложение 1: мой код в node_helper. js:

    start() {
    console.log("Starting module helper: " + this.name);
    //  console.log("Pfad zur csv-Datei: " + this.path + "/data/birthdays.csv");

    const csvFilePath = this.path + '/data/birthdays.csv';
    csv()
    .fromFile(csvFilePath)
    .then((jsonObj)=>{      
        birthdaysArray = JSON.stringify(jsonObj);
        console.log("birthdaysArray: " + birthdaysArray);

    var result = Object.entries(birthdaysArray.reduce((a, {birth, name}) => {
        const day = +birth.split('.')[0];
        a[day] = [...(a[day] || []), name];
        return a
    }, {})).map(([day, name]) => ({day, name})).sort((a, b) => +a.day - b.day)
    console.log("sorted birthdays : " + result);
    })
}

=> output console.log:

  Unhandled rejection TypeError: birthdaysArray.reduce is not a function
at /home/dirk/MagicMirror/modules/perlchamp/node_helper.js:27:47
at Object.onfulfilled (/home/dirk/MagicMirror/node_modules/csvtojson/v2/Converter.js:112:33)
at Result.endProcess (/home/dirk/MagicMirror/node_modules/csvtojson/v2/Result.js:83:50)
at Converter.processEnd (/home/dirk/MagicMirror/node_modules/csvtojson/v2/Converter.js:179:21)
at /home/dirk/MagicMirror/node_modules/csvtojson/v2/Converter.js:172:19
at tryCatcher (/home/dirk/MagicMirror/node_modules/bluebird/js/release/util.js:16:23)
at Promise._settlePromiseFromHandler (/home/dirk/MagicMirror/node_modules/bluebird/js/release/promise.js:547:31)
at Promise._settlePromise (/home/dirk/MagicMirror/node_modules/bluebird/js/release/promise.js:604:18)
at Promise._settlePromise0 (/home/dirk/MagicMirror/node_modules/bluebird/js/release/promise.js:649:10)
at Promise._settlePromises (/home/dirk/MagicMirror/node_modules/bluebird/js/release/promise.js:729:18)
at _drainQueueStep (/home/dirk/MagicMirror/node_modules/bluebird/js/release/async.js:93:12)
at _drainQueue (/home/dirk/MagicMirror/node_modules/bluebird/js/release/async.js:86:9)
at Async._drainQueues (/home/dirk/MagicMirror/node_modules/bluebird/js/release/async.js:102:5)
at Immediate.Async.drainQueues [as _onImmediate] (/home/dirk/MagicMirror/node_modules/bluebird/js/release/async.js:15:14)
at processImmediate (internal/timers.js:439:21)

так, что я могу сделать?

вложение 2: сначала я хотел отфильтровать строку по месяцам:

        var today_month = moment().format("MM")
        var monthList = [];

        for(let prop in jsonObj) {
            if (jsonObj[prop]["birth"].split(".")[1] == today_month) {
                //console.log("fifth: ", jsonObj[prop]);
                monthList += jsonObj[prop];
            }
        }
        console.log("monthList: ", monthList);

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

Ответы [ 2 ]

1 голос
/ 01 мая 2020

Цель состоит в том, чтобы создать Массив из Объект s, структура которого [{ day: String, name: [String] }, …]. Отметив, что повторяющиеся дней будут сгруппированы в один и тот же Объект , который день указывает на группировку.

Входные данные представляют собой массив чей формат [{ birth: String, name: String }, …]. Во-первых, вы захотите извлечь значимый день месяца из строки даты, которая не отформатирована стандартным способом (например, "25.04.1988").

Чтобы преобразовать эту String Вы можете использовать регулярное выражение с параметром обратного вызова, который упорядочивает дату в формате ISO-8601 Date , который стандарт ECMA предусматривает, что Date должен поддерживать в его строительстве. Также обратите внимание, что Date ожидает, что его ввод будет в UT C времени, т. Е. Он не знает о часовом поясе.

Такая конструкция может выглядеть как

const input = new Date('23.04.1988'.replace(/^(\d+)[^\d+](\d+)[^\d+](\d+)$/, (...backRefs) => {
    return `${backRefs[3]}-${backRefs[2]}-${backRefs[1]}`;
}));

Здесь используется синтаксис ECMAScript (который Node.js реализует) для объявления литерала регулярного выражения: /RegularExpressionBody/RegularExpressionFlags, где флаги пусты, а тело выражения ^(\d+)[^\d+](\d+)[^\d+](\d+)$.

Это регулярное выражение не соответствует действительной дате, но вместо этого любая конструкция из трех серий цифр (\d+), разбитых нечислительными c символами [^\d+], что составляет целую строку . Затем он восстанавливает их, используя обратные ссылки в порядке 3-2-1 с разделительными чертами в соответствии с форматом ISO-8601 Date .

Это часть `${backRefs[3]}-${backRefs[2]}-${backRefs[1]}`, который использует литералов шаблона , часто называемый неправильно строкой шаблона s.

Создание даты объекта из этого нового переменная const input будет работать, но метод toString() вернет String "Invalid Date", если он действительно недопустим. Если введенная дата не соответствует регулярному выражению, так что обратная ссылка индексирует группу захвата, которая не захватывает; тогда тип построенного Дата равен undefined, поскольку он будет создан с недопустимыми входами. Этот конкретный результат может быть использован для агрегирования неверных дат рождения. Теперь, когда вы знаете, как правильно извлечь день, вы можете приступить к сортировке и группировке входных данных.

const input = [{
    "birth" : "23.04.1988",
    "name": "Tom Smith"
},
{
    "birth": "15.04.2010",
    "name": "Mini Jall"
},
{
    "birth": "23.04.2001",
    "name":"Michael Bird"
}];

Пусть input будет вашим вводом Массив из Объект s.

Array Object предоставляет функцию с именем map на его прототипе , которую вы можете используйте на input, так как это Array . Спецификация Function Array.prototype.map(callbackFn[, thisArg]). Он вызывается один раз для каждого элемента, который существует в Array , который является объектом , через который проходит . Возвращенное значение обратного вызова заменяет исходный объект во временном массиве , который возвращается map после завершения. Другими словами, вы можете отобразить ваш Array в новую структуру, возвращая эту структуру из обратного вызова, используя свойства каждого элемента во время итерации. Обратите внимание, что аргумент thisArg является контекстом, в котором вызывается map Функция , и что если вы вызываете input.map, то контекст наследуется как input, и поэтому thisArg только необязательно.

Такой вызов будет выглядеть как input.map(argumentsList), где argumentsList - это список, содержащий только обратный вызов Функция . Обратный вызов принимает до трех параметров: currentValue, currentInndex и объект, по которому осуществляется обход.

Таким образом, ваш обратный вызов должен принимать форму

(curr, idx, arr) => { return…; } // or
function (curr, idx, arr) { return…; }

В этом обратном вызове вы хотите преобразовать birth параметр для day , поэтому, используя рассмотренную методологию, вы сделаете что-то вроде

let dateCB = ({ birth, name }, idx, arr) => {
    const dateString = birth.replace(/^(\d+)[^\d+](\d+)[^\d+](\d+)$/, (...backRefs) => {
        return `${backRefs[3]}-${backRefs[2]}-${backRefs[1]}`;
    });
    const date = new Date(dateString);
    const retObj = { day: date.getDate(), month: date.getUTCMonth() + 1, name };
    Object.defineProperty(retObj, 'month', { enumerable: false });

    return retObj;
};

Мы добавим 1 к месяцу, потому что getUTCMonth возвращает нулевой индексированный месяц года. Также мы определяем свойство month как не перечисляемое, поскольку не хотим, чтобы оно отображалось в объекте результата. Обратите также внимание на то, что curr из более ранней версии был деструктурирован в { birth, name } и реструктурирован в { day: date.getDate(), month: date.getUTCMonth() + 1, name }. Деструктурирующее присваивание позволяет вам уменьшить свойства Object на имена свойств, а в argumentsList оно объявляет эти свойства как переменные в области действия функции стрелки. На самом деле это сокращение для { birth: birth, name: name }, так как они имеют тот же идентификатор, что и свойства входного объекта curr. В этот момент у вас будет Array из Object s.

[
    {
        "day" :23,
        "month": 4,
        "name": "Tom Smith"
    },
    {
        "day": 15,
        "month": 4,
        "name": "Mini Jall"
    },
    {
        "day": 23,
        "month": 4,
        "name": "Michael Bird"
    }
]

За исключением того, что свойства month не будут перечисляемыми.

Вы хотите сопоставить эти Объект s так, чтобы String name вместо этого Array из всех name родительских Object акций идентичные day и month свойства с другими Object членами Array .

Так что мы будем использовать Array.prototype.reduce, который определен как Array.prototype.reduce(callbackfn[, initialValue]). Обратный вызов Функция принимает до четырех параметров: previousValue, currentValue, currentIndex и просматриваемый объект. Если вы укажете initialValue, то reduce повторяется, начиная с первого элемента, а initialValue предоставляется для обратного вызова как previousValue. Однако, если вы пропустите initialValue, то reduce повторяется, начиная со второго элемента, предоставляя первый элемент как previousValue. То, что вы возвращаете из обратного вызова, затем передается следующей итерации как previousValue.

Мы также будем использовать Array.prototype.findIndex, который определен как Array.prototype.findIndex(predicate[, thisArg ]). Предикат Функция принимает до трех параметров и должен возвращать логический принудительный результат (например, 1, 0, true, false, undefined и др. c). findIndex вернет -1, если ни один предикат не вернет true, или вернет индекс, достигнутый им, когда это сделает первый предикат.

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

({ day: tDay, month: tMonth, name: tName }) => {
    return tDay === … && tMonth === …;
}

Мы хотим создать новый вывод Array , и мы будем перебирать ввод, используя reduce, создавая выводим как мы go. По этой причине, Reduce будет вызываться с пустым массивом в качестве необязательного второго аргумента

let reducer = (prev, { day, month, name }) => {
    if (prev.length === 0) { /// this is the first iteration, where prev is empty
        prev.push({ day, month, name: [name] });
    } else { /// this is any other iteration, now we have to search `prev`
        let where = prev.findIndex(({ day: tDay, month: tMonth, name: tName }) => {
            return tDay === day && tMonth === month;
        });

        if (where !== -1) {
            prev[where].name
                .push(name);
        } else {
            prev.push({ day, month, name: [name] });
        }
    }

    return prev;
}

И вызов выглядит как

input.map(dateCB)
    .reduce(reducer, []);

Наконец, мы смотрим на функцию Array.prototype.sort, определенную как Array.prototype.sort(comparefn). comparefn Функция получает два аргумента, x и y. Работа comparefn состоит в том, чтобы описать, как x относится к y. Сортировщик ожидает отрицательное число , возвращаемое от comparefn, если x < y, ноль, если x == y, и положительное, если x > y. x и y являются двумя членами Array , которые сортируются, и, поскольку эти элементы имеют одинаковую структуру, вы можете деструктурировать x и y как { day: xDay }, { day: yDay } и вернуть xDay - yDay для достаточного результата. В этом последнем фрагменте я представляю новую переменную cDay, которая представляет собой String представление свойства day. Я также реализую не перечисляемое свойство в конечных объектах s в Array и сортировщике на выходе.

const input = [{
	"birth" : "23.04.1988",
	"name": "Tom Smith"
},
{
	"birth": "15.04.2010",
	"name": "Mini Jall"
},
{
	"birth": "23.04.2001",
	"name":"Michael Bird"
}];

const dateCB = ({ birth, name }, idx, arr) => {
	const dateString = birth.replace(/^(\d+)[^\d+](\d+)[^\d+](\d+)$/, (...backRefs) => {
		return `${backRefs[3]}-${backRefs[2]}-${backRefs[1]}`;
	});
	const date = new Date(dateString);
	const retObj = { day: date.getDate(), month: date.getUTCMonth() + 1, name };

	return retObj;
};

const reducer = (prev, { day, month, name }) => {
	const cDay = day.toString(10);
	const retObj = { day: cDay, month, name: [name] };

	Object.defineProperty(retObj, 'month', { enumerable: false });


	if (prev.length === 0) {
		prev.push(retObj);
	} else {
		const where = prev.findIndex(({ day: tDay, month: tMonth, name: tName }) => {
			return tDay === cDay && tMonth === month;
		});

		if (where !== -1) {
			prev[where].name
				.push(name);
		} else {
			prev.push(retObj);
		}
	}

	return prev;
};

const sorter = ({ day: bDay }, { day: aDay }) => {
    return bDay - aDay;
};

const output = input.map(dateCB).reduce(reducer, []).sort(sorter);
console.log(JSON.stringify(output));
1 голос
/ 01 мая 2020

Теперь, когда вы изменили ожидаемый результат - это немного чище

var data = [{
        "birth": "23.04.1988",
        "name": "Tom Smith"
    }, {
        "birth": "15.04.2010",
        "name": "Mini Jall"
    }, {
        "birth": "23.04.2001",
        "name": "Michael Bird"
    }, {
        "birth": "17.05.2001",
        "name": "May Gibbs"
    }, {
        "birth": "04.05.2001",
        "name": "May The Force be with you"
    }, {
        "birth": "17.05.2001",
        "name": "Jenny  May"
    }
];
var currentMonth = new Date().toLocaleDateString('en', {month:'2-digit'});
var result = Object.entries(data
    .filter(({birth}) => birth.split('.')[1] === currentMonth)
    .reduce((a, {birth, name}) => {
        const day = +birth.split('.')[0];
        a[day] = [...(a[day] || []), name];
        return a
    }, {})
).map(([day, name]) => ({day, name})).sort((a, b) => +a.day - b.day);
console.log(result);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...