亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

使用嵌套 for 循環重構函數 - Javascript

使用嵌套 for 循環重構函數 - Javascript

搖曳的薔薇 2023-08-18 14:04:15
我需要刪除我創建的函數中的嵌套 for 循環。我的函數接收一個關聯數組,并根據某些屬性返回一個新數組,以便對消息進行分組以供以后使用。例如,我有兩所學校,有很多學生。所以我根據性別和年級對他們進行分組。我不知道如何重構這個函數,因為我對算法不太了解。我的邏輯是否需要被徹底抹去或者需要重新做一遍并不重要。我必須刪除第二個 for 循環。另外,我可以返回公共數組、關聯數組或只是對象。我嘗試使用相同的邏輯但不同的數據復制我的函數:var studentsArray = new Array();studentsArray["SCHOOL_1"] = [    // girls    {id: '1', school: 'SCHOOL_1', grade: 'A', message: 'Congratulations!', isMan: false},    {id: '2', school: 'SCHOOL_1', grade: 'A', message: 'Good work!', isMan: false},    {id: '3', school: 'SCHOOL_1', grade: 'A', message: 'Ok', isMan: false},    // boys    {id: '4', school: 'SCHOOL_1', grade: 'A', message: 'Congratulations!', isMan: true},    {id: '5', school: 'SCHOOL_1', grade: 'B', message: 'Good work!', isMan: true},    {id: '6', school: 'SCHOOL_1', grade: 'B', message: 'Good work!', isMan: true},    {id: '7', school: 'SCHOOL_1', grade: 'A', message: 'Congratulations!', isMan: true},    {id: '8', school: 'SCHOOL_1', grade: 'B', message: 'Good work!', isMan: true},];studentsArray["SCHOOL_2"] = [    // girls    {id: '9', school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!', isMan: false},    {id: '10', school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!', isMan: false},    {id: '11', school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!', isMan: false},    {id: '12', school: 'SCHOOL_2', grade: 'B', message: 'Good work!', isMan: false},    {id: '13', school: 'SCHOOL_2', grade: 'B', message: 'Nice!', isMan: false},    // boys    {id: '14', school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!', isMan: true},    {id: '15', school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!', isMan: true},    {id: '16', school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!', isMan: true},    {id: '17', school: 'SCHOOL_2', grade: 'B', message: 'Congratulations!', isMan: true},];
查看完整描述

3 回答

?
慕哥9229398

TA貢獻1877條經驗 獲得超6個贊

可重復使用的模塊


這是了解可重用模塊的絕佳機會。您的GroupMessages函數幾乎超過 100 行,并且與您的數據結構緊密耦合。此答案中的解決方案解決了您的特定問題,無需對之前編寫的模塊進行任何修改。


我將在這個答案的末尾提供一些代碼審查,但現在我們重命名,因為schools數組grades中的每個項目代表特定學校單個學生的單個成績 -


const grades =

  [ {id: 1, school: 'SCHOOL_1', grade: 'A', message: 'Congratulations!', isMan: false}

  , {id: 2, school: 'SCHOOL_1', grade: 'A', message: 'Good work!', isMan: false}

  , {id: 3, school: 'SCHOOL_1', grade: 'A', message: 'Ok', isMan: false}

  , {id: 4, school: 'SCHOOL_1', grade: 'A', message: 'Congratulations!', isMan: true}

  , {id: 5, school: 'SCHOOL_1', grade: 'B', message: 'Good work!', isMan: true}

  , {id: 6, school: 'SCHOOL_1', grade: 'B', message: 'Good work!', isMan: true}

  , {id: 7, school: 'SCHOOL_1', grade: 'A', message: 'Congratulations!', isMan: true}

  , {id: 8, school: 'SCHOOL_1', grade: 'B', message: 'Good work!', isMan: true}

  , {id: 9, school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!', isMan: false}

  , {id: 10, school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!', isMan: false}

  , {id: 11, school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!', isMan: false}

  , {id: 12, school: 'SCHOOL_2', grade: 'B', message: 'Good work!', isMan: false}

  , {id: 13, school: 'SCHOOL_2', grade: 'B', message: 'Nice!', isMan: false}

  , {id: 14, school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!', isMan: true}

  , {id: 15, school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!', isMan: true}

  , {id: 16, school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!', isMan: true}

  , {id: 17, school: 'SCHOOL_2', grade: 'B', message: 'Congratulations!', isMan: true}

  ]

正如您所知,JavaScript 沒有關聯數組。它也沒有任何支持使用復合鍵查找(選擇具有多個鍵的值)的本機數據結構。我們將從二叉樹模塊導入一些函數,btree為您的記錄創建一個標識符,myIdentifier并使用它來初始化您的樹,myTree-


import { nil, fromArray, inorder } from "./btree.js"


const myIdentifier = record =>

  [ record?.school ?? "noschool" // if school property is blank, group by "noschool"

  , record?.grade ?? "NA"        // if grade property is blank, group by "NA"

  , record?.isMan ?? false       // if isMan property is blank, group by false

  ]


const myTree =

  nil(myIdentifier)

二叉樹根據可定制的標識符自動處理分組,并且可以使用任意數量的分組鍵。我們將使用 basicfilter來選擇與查詢匹配的所有成績gender。fromArray選定的成績數組與處理樹更新的合并函數一起傳遞。inorder用于從樹中提取分組值 -


function groupMessages (grades, gender)

{ const t =

    fromArray

      ( myTree

      , grades.filter(x => !x.isMan || gender === "man")

      , ({ messages = [] } = {}, { message = "", ...r }) =>

          ({ ...r, messages: [ ...messages, message ]})

      )

  return Array.from(inorder(t))

}

現在讓我們看看輸出 -


console.log(groupMessages(grades, 'woman'))

[

  {

    "id": "3",

    "school": "SCHOOL_1",

    "grade": "A",

    "isMan": false,

    "messages": [

      "Congratulations!",

      "Good work!",

      "Ok"

    ]

  },

  {

    "id": "11",

    "school": "SCHOOL_2",

    "grade": "A",

    "isMan": false,

    "messages": [

      "Congratulations!",

      "Congratulations!",

      "Congratulations!"

    ]

  },

  {

    "id": "13",

    "school": "SCHOOL_2",

    "grade": "B",

    "isMan": false,

    "messages": [

      "Good work!",

      "Nice!"

    ]

  }

]

為了完成這篇文章,我們將展示以下的實現btree,


// btree.js


import { memo } from "./func.js"

import * as ordered from "./ordered.js"


const nil =

  memo

    ( compare =>

        ({ nil, compare, cons:btree(compare) })

    )


const btree =

  memo

    ( compare =>

        (value, left = nil(compare), right = nil(compare)) =>

          ({ btree, compare, cons:btree(compare), value, left, right })

    )


const isNil = t =>

  t === nil(t.compare)


const compare = (t, q) =>

  ordered.all

    ( Array.from(t.compare(q))

    , Array.from(t.compare(t.value))

    )


function get (t, q)

{ if (isNil(t))

    return undefined

  else switch (compare(t, q))

  { case ordered.lt:

      return get(t.left, q)

    case ordered.gt:

      return get(t.right, q)

    case ordered.eq:

      return t.value

  }

}


function update (t, q, f)

{ if (isNil(t))

    return t.cons(f(undefined))

  else switch (compare(t, q))

  { case ordered.lt:

      return t.cons(t.value, update(t.left, q, f), t.right)

    case ordered.gt:

      return t.cons(t.value, t.left, update(t.right, q, f))

    case ordered.eq:

      return t.cons(f(t.value), t.left, t.right)

  }

}


const insert = (t, q) =>

  update(t, q, _ => q)


const fromArray = (t, a, merge) =>

  a.reduce

    ( (r, v) =>

       update

          ( r

          , v

          , _ => merge ? merge(_, v) : v

          )

    , t

    )


function* inorder (t)

{ if (isNil(t)) return

  yield* inorder(t.left)

  yield t.value

  yield* inorder(t.right)

}


export { btree, fromArray, get, inorder, insert, isNil, nil, update }

可重用性至關重要。模塊可以導入其他模塊!上面,從和btree導入- 下面包含部分模塊 -funcordered


// func.js


function memo (f)

{ const r = new Map

  return x =>

    r.has(x)

      ? r.get(x)

      : (r.set(x, f(x)), r.get(x))

}


export { memo }

// ordered.js


const lt =

  -1


const gt =

  1


const eq =

  0


const empty =

  eq


const compare = (a, b) =>

  a < b

    ? lt

: a > b

    ? gt

: eq


const all = (a = [], b = []) =>

  a.reduce

    ( (r, e, i) =>

        concat(r, compare(e, b[i]))

    , eq

    )


const concat = (a, b) =>

  a === eq ? b : a


export { all, compare, concat, empty, eq, gt, lt }


查看完整回答
反對 回復 2023-08-18
?
慕森卡

TA貢獻1806條經驗 獲得超8個贊

我想提供一種稍微不同的方法。它同樣構建在現有功能之上,但不像該方法那樣低級別。


首先,這是我對問題的初步解決方案:


const call = (fn, ...args) => fn (...args)

const groupBy = (fn) => (xs) =>

? xs .reduce ((a, x) => call (key => ((a [key] = [... (a [key] || []), x]), a), fn (x)), {})


const groupMessages = (students, gender) =>?

? Object .values (groupBy (x => `${x.school}|${x.grade}`) (Object .values (students)?

? ? .flat ()

? ? .filter (({isMan}) => isMan == (gender == 'man'))))

? ? .map ((students) => ({

? ? ? ... students [0],

? ? ? message: students .map (s => s.message) .join ('|')

? ? }))


const students = {SCHOOL_1: [/* girls */ {id: '1', school: 'SCHOOL_1', grade: 'A', message: 'Congratulations!', isMan: false}, {id: '2', school: 'SCHOOL_1', grade: 'A', message: 'Good work!', isMan: false}, {id: '3', school: 'SCHOOL_1', grade: 'A', message: 'Ok', isMan: false}, /* boys */ {id: '4', school: 'SCHOOL_1', grade: 'A', message: 'Congratulations!', isMan: true}, {id: '5', school: 'SCHOOL_1', grade: 'B', message: 'Good work!', isMan: true}, {id: '6', school: 'SCHOOL_1', grade: 'B', message: 'Good work!', isMan: true}, {id: '7', school: 'SCHOOL_1', grade: 'A', message: 'Congratulations!', isMan: true}, {id: '8', school: 'SCHOOL_1', grade: 'B', message: 'Good work!', isMan: true}], SCHOOL_2: [/* girls */ {id: '9', school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!', isMan: false}, {id: '10', school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!', isMan: false}, {id: '11', school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!', isMan: false}, {id: '12', school: 'SCHOOL_2', grade: 'B', message: 'Good work!', isMan: false}, {id: '13', school: 'SCHOOL_2', grade: 'B', message: 'Nice!', isMan: false}, /* boys */ {id: '14', school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!', isMan: true}, {id: '15', school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!', isMan: true}, {id: '16', school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!', isMan: true}, {id: '17', school: 'SCHOOL_2', grade: 'B', message: 'Congratulations!', isMan: true}]}

? ? ? ? ?

console .log (groupMessages (students, 'woman'))

.as-console-wrapper {max-height: 100% !important; top: 0}

它使用了groupBy我經常使用的一個功能。這又取決于call,它接受一個函數和參數列表,并使用這些參數調用該函數。(我在這里使用它只是為了將局部變量保持在最低限度。)


這是有效的,并且顯然比原始代碼短得多。但它有一個真正的丑陋之處,這是許多此類 JS 代碼所共有的。它很緊湊,但操作順序很難看出。需要深入理解代碼才能看到這一點:


? ? const groupMessages = (students, gender) =>?

? ? ? Object .values (groupBy (x => `${x.school}|${x.grade}`) (Object .values (students)

? ? ? ? /* ^-- 5 */? ?/* ^-- 4 */? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/* ^-- 1 */?

? ? ? ? .flat ()? /* <-- 2 */

? ? ? ? .filter (({isMan}) => isMan == (gender == 'man'))))? /* <-- 3 */

? ? ? ? .map ((students) => ({? /* <-- 6 */

? ? ? ? ? ... students [0],

? ? ? ? ? message: students .map (s => s.message) .join ('|')

? ? ? ? }))

我傾向于使用一種pipe函數,它將一個函數的結果傳遞給下一個函數,并將該函數的結果傳遞給下一個函數,依此類推。這可以清理很多東西。但它確實需要具有具體化數組方法等內容的柯里化函數。


所以,我發現這個細分更清晰:


// reusable utility functions

const pipe = (...fns) => (arg) => fns .reduce ((a, f) => f (a), arg)

const map = (fn) => (xs) => xs .map (x => fn (x))

const filter = (fn) => (xs) => xs .filter (x => fn (x))

const call = (fn, ...args) => fn (...args)

const groupBy = (fn) => (xs) =>

? xs .reduce ((a, x) => call (key => ((a [key] = [... (a [key] || []), x]), a), fn (x)), {})

const flat = (xs) => xs .flat ()


// helper function

const groupStudentMessages = (students) => ({

? ... students [0],

? message: students .map (s => s.message) .join ('|')

})


// main function, as a pipeline

const groupMessages = (students, gender) => pipe (

? Object .values,? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/* <-- 1 */

? flat,? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/* <-- 2 */?

? filter (({isMan}) => isMan == (gender == 'man')),? ?/* <-- 3 */

? groupBy (x => `${x.school}|${x.grade}`),? ? ? ? ? ? /* <-- 4 */

? Object .values,? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/* <-- 5 */

? map (groupStudentMessages)? ? ? ? ? ? ? ? ? ? ? ? ? /* <-- 6 */

) (students)


const students = {SCHOOL_1: [/* girls */ {id: '1', school: 'SCHOOL_1', grade: 'A', message: 'Congratulations!', isMan: false}, {id: '2', school: 'SCHOOL_1', grade: 'A', message: 'Good work!', isMan: false}, {id: '3', school: 'SCHOOL_1', grade: 'A', message: 'Ok', isMan: false}, /* boys */ {id: '4', school: 'SCHOOL_1', grade: 'A', message: 'Congratulations!', isMan: true}, {id: '5', school: 'SCHOOL_1', grade: 'B', message: 'Good work!', isMan: true}, {id: '6', school: 'SCHOOL_1', grade: 'B', message: 'Good work!', isMan: true}, {id: '7', school: 'SCHOOL_1', grade: 'A', message: 'Congratulations!', isMan: true}, {id: '8', school: 'SCHOOL_1', grade: 'B', message: 'Good work!', isMan: true}], SCHOOL_2: [/* girls */ {id: '9', school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!', isMan: false}, {id: '10', school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!', isMan: false}, {id: '11', school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!', isMan: false}, {id: '12', school: 'SCHOOL_2', grade: 'B', message: 'Good work!', isMan: false}, {id: '13', school: 'SCHOOL_2', grade: 'B', message: 'Nice!', isMan: false}, /* boys */ {id: '14', school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!', isMan: true}, {id: '15', school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!', isMan: true}, {id: '16', school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!', isMan: true}, {id: '17', school: 'SCHOOL_2', grade: 'B', message: 'Congratulations!', isMan: true}]}


console .log (groupMessages (students, 'woman'))

.as-console-wrapper {max-height: 100% !important; top: 0}

我希望即使沒有注釋,主函數中的操作順序也足夠清晰。為了使這一點更加清晰,我們提取了groupStudentMessages輔助函數,并使每個管道步驟成為單行代碼。

請注意,前六個函數是非常有用的、可重用的函數。


查看完整回答
反對 回復 2023-08-18
?
牛魔王的故事

TA貢獻1830條經驗 獲得超3個贊

對我來說,你必須刪除第二個 for 循環似乎很奇怪。

但這仍然是關系數據庫要解決的問題。


查看完整回答
反對 回復 2023-08-18
  • 3 回答
  • 0 關注
  • 174 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號