第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號(hào)安全,請(qǐng)及時(shí)綁定郵箱和手機(jī)立即綁定
已解決430363個(gè)問(wèn)題,去搜搜看,總會(huì)有你想問(wèn)的

如何構(gòu)建一系列方法運(yùn)行和查找循環(huán)(??碰撞)

如何構(gòu)建一系列方法運(yùn)行和查找循環(huán)(??碰撞)

幕布斯7119047 2021-09-17 10:31:50
我所擁有的:有一些 json 配置(描述性模板),以不同順序存儲(chǔ)的方法,它看起來(lái)像:[     {    "name" : "methodA", //methodA output arguments are methodB input arguments    "inArgs" : "[arg1, arg2]",    "returnArgs" : "[arg3, arg4]"  },  {    "name" : "methodB", //methodB output arguments are methodZ input arguments    "inArgs" : "[arg3, arg5]",    "returnArgs" : "[arg6, arg7]"  },{    "name" : "methodС",    "inArgs" : "[arg1]",    "returnArgs" : "[arg10]"  },    a bunch of other methods whose input arguments are not part of methodA or methodB  .....  {    "name" : "methodZ",    "inArgs" : "[arg6, arg11]",    "returnArgs" : "[arg20]"  }]我需要按照正確的順序(鏈)來(lái)運(yùn)行這些方法,例如:methodC //the output of this method is not used as an input argument to other methodsmethodA //chain i need right ordermethodBmethodZ第二種情況[     .....  {    "name" : "methodX", //methodX output arguments are methodY input arguments    "inArgs" : ?arg1, arg2, arg3]?,    "returnArgs" : ?[arg4, arg5, arg6]?  },  {    "name" : "methodY", //methodY output arguments are methodX input arguments    "inArgs" : ?[arg4, arg5, arg7]?,    "returnArgs" : ?[arg8, arg9, arg10]?  },  ....  {    "name" : "methodZ", //methodZ output arguments are methodX input arguments( collision or cycle, so throw error )    "inArgs" : ?[arg8, arg11, arg12]?,    "returnArgs" : ?[arg3, arg13, arg14]?  },]因?yàn)橐粋€(gè)方法的輸出參數(shù)可以是另一個(gè)方法的輸入?yún)?shù)(也可以通過(guò)一系列無(wú)限嵌套的方法),所以有必要捕獲這種沖突,最好是在解析配置的階段。有人可以建議解決此類問(wèn)題的最佳解決方案嗎,到目前為止只能想到圖形。對(duì)不起我的英語(yǔ)不好。
查看完整描述

2 回答

?
楊魅力

TA貢獻(xiàn)1811條經(jīng)驗(yàn) 獲得超6個(gè)贊

我喜歡的一個(gè)答案

我開(kāi)始嘗試使用您正在尋找的 API 來(lái)解決這個(gè)問(wèn)題。我確實(shí)設(shè)法得到了一些相當(dāng)接近的東西。但這不是我個(gè)人會(huì)使用的東西。我重寫(xiě)了 API 并多次重構(gòu)了實(shí)現(xiàn),直到我想出一些我想使用的東西。下面我將討論更多我的早期步驟(這可能與您更相關(guān)),但這是我將如何使用我的版本:


const def = {

  url: (server, path, query, fragment) => `${server}/${path || ''}${query || ''}${fragment ? `#${fragment}` : ''}`,

  query: (parameters) => parameters ? '?' + Object.entries(parameters).map(([k, v]) => `${k}=${v}`).join('&') : '',

  server: (schema, port, host) => `${schema}:/\/${host}${port && (String(port) != '80') ? `:${port}` : ''}`,  

  host: (domain, subdomain) => `${subdomain ? `${subdomain}.` : ''}${domain}`,

}


const vals = {

  schema: 'https',

  port: '80',

  domain: 'example.com',

  subdomain: 'test',

  path: 'path/to/resource',

  parameters: {foo: 42, bar: 'abc'},

  fragment: 'baz',

}



runFunctions (def) (vals) 

這將生成如下輸出:


{

  schema: "https",

  port: "80",

  domain: "example.com",

  subdomain: "test",

  path: "path/to/resource",

  parameters: {foo: 42, bar: "abc"},

  fragment: "baz",

  query: "?foo=42&bar=abc",

  host: "test.example.com",

  server: "https://test.example.com",

  url: "https://test.example.com/path/to/resource?foo=42&bar=abc#baz"

}

API設(shè)計(jì)

我在這個(gè)版本中看到的主要優(yōu)點(diǎn)是 API 感覺(jué)很干凈。配置對(duì)象只是將名稱映射到函數(shù),而提供給結(jié)果函數(shù)的數(shù)據(jù)對(duì)象只是將名稱映射到這些函數(shù)所需的初始參數(shù)。結(jié)果是該數(shù)據(jù)對(duì)象的增強(qiáng)版本。初始調(diào)用返回一個(gè)可重用的函數(shù)。這一切都非常簡(jiǎn)單。


執(zhí)行

我寫(xiě)這篇文章的一些歷史已經(jīng)嵌入到設(shè)計(jì)中。它可能可以使用良好的重構(gòu);一些輔助函數(shù)可能不是必需的。但目前它包括:

  • 四個(gè)簡(jiǎn)單的輔助函數(shù):

    • isEmpty 報(bào)告數(shù)組是否為空

    • removeIndex就像一個(gè)不可變的splice,返回一個(gè)沒(méi)有第nth 個(gè)索引的數(shù)組的副本

    • props 將屬性名稱數(shù)組映射到給定對(duì)象中的值

    • error 簡(jiǎn)單地將一個(gè)字符串包裝在一個(gè)錯(cuò)誤中并拋出它

  • 一個(gè)不那么瑣碎的輔助函數(shù):

  • 四個(gè)主要功能:

    • preprocess將我們的描述對(duì)象轉(zhuǎn)換為一個(gè)配置對(duì)象,該對(duì)象看起來(lái)類似于問(wèn)題中描述的結(jié)構(gòu)(帶有nameinArgs屬性,但沒(méi)有屬性returnArgs。)

    • makeGraphconverts 將配置對(duì)象轉(zhuǎn)換為鄰接圖(具有name字符串和字符串?dāng)?shù)組的對(duì)象predecessors數(shù)組。)

    • sortGraph對(duì)鄰接圖執(zhí)行拓?fù)渑判?。它是從我?a >https://stackoverflow.com/a/54408852/ 上寫(xiě)的一個(gè)借來(lái)的,但如果圖形是循環(huán)的,則可以通過(guò)拋出錯(cuò)誤的能力得到增強(qiáng)。

    • process接受配置對(duì)象和排序圖并生成一元函數(shù)。該函數(shù)接受一個(gè)上下文對(duì)象并將這些函數(shù)應(yīng)用到該對(duì)象的屬性上,將一個(gè)新值添加到以函數(shù)名稱為鍵的對(duì)象中。這將調(diào)用makeGraph然后sortGraph在結(jié)果上。

  • 最后,一個(gè)小的包裝函數(shù):

    • runFunctions接受一個(gè)描述對(duì)象,調(diào)用preprocess它來(lái)創(chuàng)建配置對(duì)象,將它傳遞給process并返回結(jié)果函數(shù)。

我確信有一種合理的重構(gòu)可以消除對(duì)中間配置對(duì)象和/或結(jié)合了圖形的創(chuàng)建和排序的需求。這留給讀者作為練習(xí)!

完整示例

// helpers

const isEmpty = arr =>

  arr .length == 0

const removeIndex = (n, arr) =>

  arr .slice (0, n) .concat (arr .slice (n + 1) )

const props = (names) => (obj) => 

  names .map (name => obj [name] )

const error = (msg) => {

  throw new Error (msg)

}

// retrieves parameter named from a function (https://stackoverflow.com/a/9924463)

const parseArgs = (func) => {

  var fnStr = func.toString().replace( /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg, '');

  var result = fnStr.slice(fnStr.indexOf('(')+1, fnStr.indexOf(')')).match(/([^\s,]+)/g);

  if(result === null)

     result = [];

  return result;

}



// chooses an appropriate order for our digraph, throwing error on circular

const sortGraph = (

  graph,

  sorted = [],

  idx = graph .findIndex (node => isEmpty (node.predecessors) ),

  nodeName = (graph [idx] || {}) .name

) => isEmpty (graph)

  ? sorted

  : idx < 0

    ? error ('function definitions contains cycle')

    : sortGraph (

      removeIndex (idx, graph) .map (({name, predecessors}) => ({

        name,

        predecessors: predecessors .filter (n => n !== nodeName)

      }), graph),

      sorted .concat (nodeName)

    )


// turns a config into an adjacensy graph

const makeGraph = config =>

  Object .entries (config) .map (([name, {inArgs}]) => ({

    name,

    predecessors: inArgs .filter (name => name in config)

  }) )



// turns a config object into a function that will run its

// functions in an appropriate order

const process = (config, order = sortGraph (makeGraph (config) )) =>

  (vals) =>

    order .reduce

      ( (obj, name) => ({

        ...obj, 

        [name]: config [name] .fn .apply (obj, props (config [name] .inArgs) (obj) )

      })

      , vals

      )


// converts simpler configuration into complete version

const preprocess = (def) => 

  Object .entries (def) .reduce

    ( (obj, [name, fn]) => ( { ...obj, [name]: {fn, inArgs: parseArgs(fn)}      })

    , {}

    )



// main function

const runFunctions = (def) => 

  process (preprocess (def) )



// input definition

const def = {

  url: (server, path, query, fragment) => `${server}/${path || ''}${query || ''}${fragment ? `#${fragment}` : ''}`,

  query: (parameters) => parameters ? '?' + Object.entries(parameters).map(([k, v]) => `${k}=${v}`).join('&') : '',

  server: (schema, port, host) => `${schema}:/\/${host}${port && (String(port) != '80') ? `:${port}` : ''}`,  

  host: (domain, subdomain) => `${subdomain ? `${subdomain}.` : ''}${domain}`,

}


// initial input object

const vals = {

  schema: 'https',

  port: '80',

  domain: 'example.com',

  subdomain: 'test',

  path: 'path/to/resource',

  parameters: {foo: 42, bar: 'abc'},

  fragment: 'baz',

}



console .log (

  runFunctions (def) (vals)

)

與請(qǐng)求設(shè)計(jì)的差異

問(wèn)題中的 API 不同:配置對(duì)象看起來(lái)更像:


[{

  name: 'makeUrl',

  inArgs: '[domain, subdomain]',

  returnArgs: '[host]',

}, /* ... */]

即使經(jīng)過(guò)一些清理,也會(huì)看起來(lái)像這樣:


[{

  name: 'makeHost',

  inArgs: ['domain', 'subdomain'],

  returnArgs: ['host'],

}, /* ... */]

這比我的解決方案更靈活,因?yàn)樗试S從單個(gè)函數(shù)返回多個(gè)返回值,并封裝在一個(gè)數(shù)組中。但是如果在實(shí)現(xiàn)中沒(méi)有一些不舒服的體操,它也需要每個(gè)函數(shù)的多次返回。此外,它要求無(wú)論您為此提供什么函數(shù),您都必須將函數(shù)與名稱分開(kāi)匹配,您必須確保參數(shù)名稱和順序與inArgs參數(shù)完全匹配,并且您必須包裝更常見(jiàn)的標(biāo)量以數(shù)組形式返回。這可能看起來(lái)像這樣:


const fns = {

  makeHost: (domain, subdomain) => [`${subdomain ? `${subdomain}.` : ''}${domain}`],

  /* ... */

}

我的初步方法

在我看來(lái),添加第二個(gè)配置參數(shù)并使它們保持同步會(huì)使 API 更不符合人體工程學(xué)。但它可以做到,這就是我第一次解決這個(gè)問(wèn)題的方式。


這個(gè)版本需要更少的輔助函數(shù)。不需要preprocess或parseArgs。 props添加只是為了簡(jiǎn)化上面的重構(gòu)版本。我還沒(méi)有檢查它是否對(duì)這個(gè)有幫助。


請(qǐng)注意,process這里要復(fù)雜得多,而且makeGraph稍微復(fù)雜一些。那是因?yàn)樘幚矶鄠€(gè)返回參數(shù)會(huì)增加一些工作??偟膩?lái)說(shuō),這個(gè)版本比上面的版本短了幾行。當(dāng)您創(chuàng)建更舒適的 API 時(shí),這通常是權(quán)衡。但個(gè)別功能不那么復(fù)雜。


執(zhí)行

您可以展開(kāi)此代碼段以查看完整示例:

// helpers

const isEmpty = arr =>

  arr .length == 0

const removeIndex = (n, arr) =>

  arr .slice (0, n) .concat (arr .slice (n + 1))

const error = (msg) => {

  throw new Error (msg)

}


// chooses an appropriate order for our digraph, throwing error on circular

const sortGraph = (

  graph,

  sorted = [],

  idx = graph .findIndex (node => isEmpty (node.predecessors) ),

  nodeName = (graph [idx] || {}) .name

) => isEmpty (graph)

  ? sorted

  : idx < 0

    ? error ('contains cycle')

    : sortGraph (

      removeIndex (idx, graph) .map (({name, predecessors}) => ({

        name,

        predecessors: predecessors .filter (n => n !== nodeName)

      }), graph),

      sorted .concat (nodeName)

    )


// turns a config into an adjacensy graph

const makeGraph = config =>

  config .map (({name, inArgs}) => ({

    name,

    predecessors: inArgs .flatMap (

      input => config

        .filter ( ({returnArgs}) => returnArgs .includes (input) )

        .map ( ({name}) => name )

    )

  }) )


// main function

const process = (config) => (fns, order = sortGraph (makeGraph (config) )) =>

  (vals) =>

    order .reduce

      ( (obj, name) => {

          const {inArgs, returnArgs} = config .find

            ( node => node .name == name

            )

          const args = inArgs .map (key => obj [key])

          const res = fns [name] .apply (obj, args)

          return returnArgs .reduce

            ( (o, k, i) => ({...o, [k]: res [i]})

            , obj

            )

        }

      , vals

      )



const config = [

  {name: 'host', inArgs: ['domain', 'subdomain'], returnArgs: ['host']},

  {name: 'server', inArgs: ['schema', 'port', 'host'], returnArgs: ['server']},

  {name: 'query', inArgs: ['parameters'], returnArgs: ['query']},

  {name: 'url', inArgs: ['server', 'path', 'query', 'fragment'], returnArgs: ['url']}

]


const fns = {

  host: (domain, subdomain) => [`${subdomain ? `${subdomain}.` : ''}${domain}`],

  server: (schema, port, host) => 

    [`${schema}:/\/${host}${port && (String(port) != '80') ? `:${port}` : ''}`],

  query: (parameters) => [parameters ? '?' + Object.entries(parameters).map(([k, v]) => `${k}=${v}`).join('&') : ''],

  url: (server, path, query, fragment) => [`${server}/${path || ''}${query || ''}${fragment ? `#${fragment}` : ''}`]

}


const vals = {

  schema: 'https',

  port: '80',

  domain: 'example.com',

  subdomain: 'test',

  path: 'my/path',

  parameters: {foo: 42, bar: 'abc'},

  fragment: 'baz',

}



console .log (

  process (config) (fns) (vals)

)

中間工作

我什至不會(huì)嘗試顯示我的代碼在初始版本和最終版本之間經(jīng)歷的所有階段,但是 API 中有一個(gè)有趣的路標(biāo),我在其中使用了這樣的配置對(duì)象:


const config = {

  host: {

    inArgs: ['domain', 'subdomain'], 

    fn: (domain, subdomain) => `${subdomain ? `${subdomain}.` : ''}${domain}`,

  },

  /* ... */

}

該版本有一些話要說(shuō):它避免了解析函數(shù)以獲取參數(shù)的需要。如何動(dòng)態(tài)獲取函數(shù)參數(shù)名稱/值的各種脆弱答案?證明這是一個(gè)不平凡的問(wèn)題。Angular 的依賴注入的用戶應(yīng)該對(duì)它非常熟悉。


但最終,這太干凈了:


const config = {

  host: fn: (domain, subdomain) => `${subdomain ? `${subdomain}.` : ''}${domain}`,

  /* ... */

}

因此我更喜歡我的最終版本。


結(jié)論

這是一個(gè)不平凡的問(wèn)題。


在這些版本中的任何一個(gè)中,實(shí)現(xiàn)都不是特別困難。但是將其分解為有用的部分是具有挑戰(zhàn)性的。當(dāng)我們可以靈活地選擇任何看起來(lái)正確的東西時(shí),確定一個(gè)有用的 API 可能需要大量的思考、大量的討論和大量的嘗試。


不同的開(kāi)發(fā)人員會(huì)做出不同的選擇,通常是出于重要的原因,但對(duì)我來(lái)說(shuō),犧牲可能罕見(jiàn)的設(shè)施來(lái)從單個(gè)函數(shù)中獲得多個(gè)回報(bào)是完全值得的,以實(shí)現(xiàn)一個(gè)更簡(jiǎn)單的配置對(duì)象。事實(shí)上,很難想象一個(gè)更簡(jiǎn)單的配置。


查看完整回答
反對(duì) 回復(fù) 2021-09-17
?
冉冉說(shuō)

TA貢獻(xiàn)1877條經(jīng)驗(yàn) 獲得超1個(gè)贊

一個(gè)更簡(jiǎn)單但并非萬(wàn)無(wú)一失(您無(wú)法檢測(cè)循環(huán))的解決方案是將每個(gè)值包裝到一個(gè) Promise 中:當(dāng)一個(gè)函數(shù)生成某些輸出時(shí),解析 Promise,然后Promise.all在輸入上使用。這樣,promise 將自動(dòng)確定正確的順序:


const context = { /* [var: string]: { resolve(v: T), value: Promise<T> */ };


function getVar(name) {

 if(context[name]) return context[name].value;

 const cont = context[name] = { };

 return cont.value = new Promise(res => cont.resolve = res);

}


function setVar(name, value) {

 getVar(name); // Make sure prop is initialized, don't await!

 context[name].resolve(value);

}


async function run(fn, argNames, resultNames) {

   const args = await Promise.all(argNames.map(getVar));

   const results = fn(...args);

   for(let i = 0; i < results.length; i++)

     setVar(resultNames[i], results[i]);

}


查看完整回答
反對(duì) 回復(fù) 2021-09-17
  • 2 回答
  • 0 關(guān)注
  • 156 瀏覽
慕課專欄
更多

添加回答

舉報(bào)

0/150
提交
取消
微信客服

購(gòu)課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動(dòng)學(xué)習(xí)伙伴

公眾號(hào)

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號(hào)