簡體   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