繁体   English   中英

使用 javascript 循环遍历 json-Array

[英]loop through a json-Array with javascript

我在nodejs中循环使用javascript的json数组时遇到问题。 我的名为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)的条目应在相同日期列出。 它应该看起来像,如果4 月是当前月份(列表有 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 控制台日志:

  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 中做到这一点吗? 因此,按当月从年度生日列表中过滤,然后按我上面提到的那样显示这些条目。

现在你改变了预期的结果——它更干净了

 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);

目标是创建一个Object数组,其结构为[{ day: String, name: [String] }, …] 请注意,重复的日期将被分组到相同的Object中,日期指示分组。

输入数据是一个数组,其格式为[{ birth: String, name: String }, …]


首先,您需要从没有以标准方式格式化的日期字符串(例如"25.04.1988" )中提取一个有意义的日期。

要转换此字符串,您可以使用带有回调参数的正则表达式,该参数以ISO-8601 日期格式对日期进行排序, ECMA标准规定Date在其构造中必须支持。 另请注意, Date期望其输入为 UTC 时间,即它不知道时区。

这样的结构可能看起来像

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+)的任何构造匹配,由构成整个String的非数字字符[^\d+]打破。 然后,它使用3-2-1顺序的反向引用重建它们,并按照ISO-8601 Date的格式用破折号分隔它们。

那就是`${backRefs[3]}-${backRefs[2]}-${backRefs[1]}`部分,它利用了经常被错误地称为模板字符串的模板文字。

从这个新的变量const input构造一个Date Object是可行的,但是如果它确实是无效的,它的toString()方法将返回字符串"Invalid Date" 如果输入日期与正则表达式不匹配,则反向引用索引未捕获的捕获组; 那么构造的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成为Object的输入数组

阵列Object在其原型上提供了一个名为mapmap ,您可以在input上使用它,因为它是一个阵列 这个Function的规范是Array.prototype.map(callbackFn[, thisArg]) 它为数组存在的每个元素调用一次,即被遍历的 object 回调的返回值替换了临时数组中的原始 object,该临时数组map在完成时返回。 换句话说,您可以通过在迭代时使用每个元素的属性从回调中返回该结构来将您的数组map 转换为新结构。 请注意,参数thisArg是调用map Function的上下文,并且如果您调用input.map则只有上下文作为input继承,因此thisArg是可选的。

这样的调用看起来像input.map(argumentsList)其中argumentsList是一个仅包含回调Function的列表。 回调最多需要三个参数:currentValue、currentIndex 和正在遍历的 object。

所以你的回调应该采取以下形式

(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定义为不可枚举,因为我们不希望它出现在结果 object 中。 另请注意,之前的curr{ birth, name }中被解构并在{ day: date.getDate(), month: date.getUTCMonth() + 1, name }中重新构建。 解构赋值允许您将Object属性减少为属性名称,并在argumentsList中将这些属性声明为箭头 ZC1C425268E68385D1AB4ZZC17A94F 的 scope 中的变量。 这实际上是{ birth: birth, name: name }的简写,因为它们具有与输入 object curr的属性相同的标识符。


此时,您将拥有一个Object数组

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

除了不能枚举month属性。

您想要整理这些Object s,以便String name是所有name s 的Array ,其父ObjectArray的其他Z497031794414A552435F9015B成员共享相同的daymonth属性。

所以我们将考虑使用定义为Array.prototype.reduce Array.prototype.reduce(callbackfn[, initialValue])的 Array.prototype.reduce。 回调Function最多需要四个参数:previousValue、currentValue、currentIndex 和正在遍历的 object。 如果您提供initialValue ,则reduce从第一个元素开始迭代,并将initialValue作为previousValue提供给回调。 但是,如果您省略initialValue ,则reduce从第二个元素开始的迭代,提供第一个元素作为previousValue 然后,您从回调返回的内容将作为其previousValue传递给下一次迭代。

我们还将使用定义为Array.prototype.findIndex Array.prototype.findIndex(predicate[, thisArg ])的 Array.prototype.findIndex。 谓词Function最多需要三个参数,并且应该返回 boolean 强制结果(例如10truefalseundefined等)。 如果没有谓词返回truefindIndex将返回-1 ,否则它将返回它在第一个谓词返回时达到的索引。

我们可以使用它来确定数组是否包含匹配的daymonth ,以用于 reducer 的迭代。

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

我们要构造一个新的数组output 并且我们将使用reduce遍历输入,构造 output 就像我们 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, []);


最后我们看看 function Array.prototype.sort定义为Array.prototype.sort(comparefn) comparefn Function接收两个 arguments, xy comparefn的工作是描述xy的关系。 如果x < y ,则排序器期望从comparefn返回comparefn ,如果x == y则返回零,如果x > y则返回正数。 xy是要排序的Array的两个成员,因此由于这些成员具有相同的结构,您可以将xy解构为{ day: xDay }, { day: yDay }并返回xDay - yDay以获得足够的结果。
在最后一个片段中,我引入了一个新变量cDay ,它只是day属性的字符串表示形式。 我还在数组中的最终Object和 output 上的排序器上实现了不可枚举的属性。
 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));

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM