返回与特定分支遍历匹配的对象。

huangapple go评论99阅读模式
英文:

Return object that matches specific branch traversal

问题

这个问题起源于这里

给定此数据:

  1. {
  2. "tabs-3": {
  3. "Collection A": {
  4. "Level 2": {
  5. "Data A": {
  6. "tab3graph25": {
  7. "30/04": 21750,
  8. "31/03": 19428,
  9. "29/05": 20955
  10. }
  11. }
  12. }
  13. },
  14. "Collection B": {
  15. "Level 2": {
  16. "Data A": {
  17. "tab3graph33": {
  18. "30/04": 56863,
  19. "31/03": 62298,
  20. "29/05": 56044
  21. }
  22. }
  23. }
  24. },
  25. "Collection C": {
  26. "Level 2": {
  27. "Data A": {
  28. "tab3graph40": {
  29. "30/04": 56044,
  30. "31/03": 62298,
  31. "29/05": 56863
  32. }
  33. }
  34. }
  35. }
  36. }
  37. }

函数的形式是这样的,它将以对象和搜索列表作为输入,例如,var searchList = [Collection B, Level 2, Data A],然后返回tab3graph33:{...values...}

初始函数可参考如下:

  1. function searchObjectForValues(obj, searchList) {
  2. var matchingObjects = {};
  3. function recursiveSearch(currentObj, path) {
  4. if (typeof currentObj === 'object' && currentObj !== null) {
  5. for (var key in currentObj) {
  6. if (currentObj.hasOwnProperty(key)) {
  7. var value = currentObj[key];
  8. var currentPath = path.concat(key);
  9. if (searchList.includes(key)) {
  10. matchingObjects[key] = currentObj[key];
  11. }
  12. recursiveSearch(value, currentPath);
  13. }
  14. }
  15. }
  16. }
  17. recursiveSearch(obj, []);
  18. return matchingObjects;
  19. }
英文:

This question started here

The conversation exceeded the original scope, so asking the expanded question here.

Given this data:

  1. {
  2. "tabs-3": {
  3. "Collection A": {
  4. "Level 2": {
  5. "Data A": {
  6. "tab3graph25": {
  7. "30/04": 21750,
  8. "31/03": 19428,
  9. "29/05": 20955
  10. }
  11. }
  12. }
  13. }
  14. "Collection B": {
  15. "Level 2": {
  16. "Data A": {
  17. "tab3graph33": {
  18. "30/04": 56863,
  19. "31/03": 62298,
  20. "29/05": 56044
  21. }
  22. }
  23. }
  24. }
  25. "Collection C": {
  26. "Level 2": {
  27. "Data A": {
  28. "tab3graph40": {
  29. "30/04": 56044,
  30. "31/03": 62298,
  31. "29/05": 56863
  32. }
  33. }
  34. }
  35. }
  36. }

}

What would a function look like that would take as it's input the holding object to search, in this case, "tabs-3", and a key set to look for, e.g., var searchList = [Collection B, Level 2, Data A] and then return "tab3graph33:{...values...}

The original starting function I have is here for reference ,

  1. function searchObjectForValues(obj, searchList) {
  2. var matchingObjects = {};
  3. function recursiveSearch(currentObj, path) {
  4. if (typeof currentObj === 'object' && currentObj !== null) {
  5. for (var key in currentObj) {
  6. if (currentObj.hasOwnProperty(key)) {
  7. var value = currentObj[key];
  8. var currentPath = path.concat(key);
  9. if (searchList.includes(key)) {
  10. matchingObjects[key] = currentObj[key];
  11. }
  12. recursiveSearch(value, currentPath);
  13. }
  14. }
  15. }
  16. }
  17. recursiveSearch(obj, []);
  18. return matchingObjects;
  19. }

Although the answers in the original question are much more elegant than mine.

答案1

得分: 1

我们可以为此编写一个相当简单的递归函数。通常,实用程序库中已经包含了这样一个函数,如果您已经在使用类似 Underscore 或 Ramda 的东西的话。

  1. const getPath = ([p, ...ps]) => (o) =>
  2. p == undefined ? o : getPath(ps)(o && o[p])
  3. const data = {
  4. "tabs-3": {
  5. "Collection A": {
  6. "Level 2": {
  7. "Data A": {
  8. tab3graph25: {
  9. "30/04": 21750,
  10. "31/03": 19428,
  11. "29/05": 20955
  12. }
  13. }
  14. },
  15. "Collection B": {
  16. "Level 2": {
  17. "Data A": {
  18. tab3graph33: {
  19. "30/04": 56863,
  20. "31/03": 62298,
  21. "29/05": 56044
  22. }
  23. }
  24. }
  25. },
  26. "Collection C": {
  27. "Level 2": {
  28. "Data A": {
  29. tab3graph40: {
  30. "30/04": 56044,
  31. "31/03": 62298,
  32. "29/05": 56863
  33. }
  34. }
  35. }
  36. }
  37. }
  38. }
  39. }
  40. const tabs3 = data['tabs-3']
  41. console.log('Partial path:', getPath(['Collection B', 'Level 2', 'Data A'])(tabs3))
  42. // 或者
  43. console.log('Full-path:', getPath(['tabs-3', 'Collection B', 'Level 2', 'Data A'])(data))

第一个 console.log 显示了您可能希望使用的方式,其中引用了数据中 'tabs-3' 属性中的对象。第二个示例展示了我更喜欢的方式,将 'tabs-3' 作为属性列表中的一个属性。

英文:

We can write a fairly simple recursive function for this. Utility libraries usually include one, too, if you're already using something like Underscore or Ramda.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

  1. const getPath = (

    ) =&gt; (o) =&gt;

  2. p == undefined ? o : getPath(ps) (o &amp;&amp; o

    )

  3. const data = {&quot;tabs-3&quot;: {&quot;Collection A&quot;: {&quot;Level 2&quot;: {&quot;Data A&quot;: {tab3graph25: {&quot;30/04&quot;: 21750, &quot;31/03&quot;: 19428, &quot;29/05&quot;: 20955}}}}, &quot;Collection B&quot;: {&quot;Level 2&quot;: {&quot;Data A&quot;: {tab3graph33: {&quot;30/04&quot;: 56863, &quot;31/03&quot;: 62298, &quot;29/05&quot;: 56044}}}}, &quot;Collection C&quot;: {&quot;Level 2&quot;: {&quot;Data A&quot;: {tab3graph40: {&quot;30/04&quot;: 56044, &quot;31/03&quot;: 62298, &quot;29/05&quot;: 56863}}}}}}

  4. const tabs3 = data[&#39;tabs-3&#39;]

  5. console .log (&#39;Partial path:&#39;, getPath ([&#39;Collection B&#39;, &#39;Level 2&#39;, &#39;Data A&#39;])(tabs3))

  6. // or

  7. console .log (&#39;Full-path:&#39;, getPath ([&#39;tabs-3&#39;, &#39;Collection B&#39;, &#39;Level 2&#39;, &#39;Data A&#39;])(data))

<!-- language: lang-css -->

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

<!-- end snippet -->

The first console.log shows how you would use this the way you seem to want, with a reference to the object in the &#39;tabs-3&#39; property of your data. The second one shows my preferred way, using &#39;tabs-3&#39; as one more property in the list.

答案2

得分: 1

以下是您请求的翻译部分:

这是一个有趣的get函数,它接受***通配符。给定这个data -

  1. const data = {
  2. a: {
  3. b: {
  4. x: {y:1, z:2},
  5. y: {z:3},
  6. },
  7. c: {
  8. x: {y:4},
  9. y: {z:5},
  10. },
  11. d: {x:6},
  12. },
  13. b: {c: {z:7}}
  14. }

我们可以将get写成一个递归生成器 -

  1. function *get(t, path) {
  2. function *loop(t, path, match, wild) {
  3. if (path.length === 0)
  4. yield [match, t]
  5. else if (path[0] === &quot;**&quot;)
  6. yield *loop(t, path.slice(1), match, true)
  7. else if (Object(t) === t)
  8. for (const k of Object.keys(t))
  9. if (path[0] === &quot;*&quot; || path[0] === k)
  10. yield *loop(t[k], path.slice(1), [...match, k], false)
  11. else if (wild)
  12. yield *loop(t[k], path, [...match, k], true)
  13. }
  14. yield *loop(t, path, [], false)
  15. }

搜索以a开头,然后跟一个通配符,然后是x的路径 -

  1. for (const [path, value] of get(data, [&quot;a&quot;,&quot;*&quot;,&quot;x&quot;]))
  2. console.log(
  3. JSON.stringify(path),
  4. JSON.stringify(value)
  5. )
  1. [&quot;a&quot;,&quot;b&quot;,&quot;x&quot;] {&quot;y&quot;:1,&quot;z&quot;:2}
  2. [&quot;a&quot;,&quot;c&quot;,&quot;x&quot;] {&quot;y&quot;:4}
  3. [&quot;a&quot;,&quot;d&quot;,&quot;x&quot;] 6

搜索以z结尾的任何路径 -

  1. for (const [path, value] of get(data, [&quot;**&quot;,&quot;z&quot;]))
  2. console.log(
  3. JSON.stringify(path),
  4. JSON.stringify(value)
  5. )
  1. [&quot;a&quot;,&quot;b&quot;,&quot;x&quot;,&quot;z&quot;] 2
  2. [&quot;a&quot;,&quot;b&quot;,&quot;y&quot;,&quot;z&quot;] 3
  3. [&quot;a&quot;,&quot;c&quot;,&quot;y&quot;,&quot;z&quot;] 5
  4. [&quot;b&quot;,&quot;c&quot;,&quot;z&quot;] 7

获取完整路径acxy -

  1. for (const [path, value] of get(data, [&quot;a&quot;,&quot;c&quot;,&quot;x&quot;,&quot;y&quot;]))
  2. console.log(
  3. JSON.stringify(path),
  4. JSON.stringify(value)
  5. )
  1. [&quot;a&quot;,&quot;c&quot;,&quot;x&quot;,&quot;y&quot;] 4

创建复杂的模式 -

  1. for (const [path, value] of get(data, [&quot;*&quot;,&quot;b&quot;,&quot;**&quot;,&quot;y&quot;]))
  2. console.log(
  3. JSON.stringify(path),
  4. JSON.stringify(value)
  5. )
  1. [&quot;a&quot;,&quot;b&quot;,&quot;x&quot;,&quot;y&quot;] 1
  2. [&quot;a&quot;,&quot;b&quot;,&quot;y&quot;] {&quot;z&quot;:3}

获取不存在的路径 -

  1. for (const [path, value] of get(data, [&quot;x&quot;,&quot;y&quot;,&quot;z&quot;]))
  2. console.log(
  3. JSON.stringify(path),
  4. JSON.stringify(value)
  5. )
  1. // &lt;empty result&gt;
英文:

Here's a fun get function which accepts * and ** wildcards. Given this data -

  1. const data = {
  2. a: {
  3. b: {
  4. x: {y:1, z:2},
  5. y: {z:3},
  6. },
  7. c: {
  8. x: {y:4},
  9. y: {z:5},
  10. },
  11. d: {x:6},
  12. },
  13. b: {c: {z:7}}
  14. }

We can write get as a recursive generator -

  1. function *get(t, path) {
  2. function *loop(t, path, match, wild) {
  3. if (path.length === 0)
  4. yield [match, t]
  5. else if (path[0] === &quot;**&quot;)
  6. yield *loop(t, path.slice(1), match, true)
  7. else if (Object(t) === t)
  8. for (const k of Object.keys(t))
  9. if (path[0] === &quot;*&quot; || path[0] === k)
  10. yield *loop(t[k], path.slice(1), [...match, k], false)
  11. else if (wild)
  12. yield *loop(t[k], path, [...match, k], true)
  13. }
  14. yield *loop(t, path, [], false)
  15. }

Search for a path starting with a, followed by one wildcard, followed by x -

  1. for (const [path, value] of get(data, [&quot;a&quot;,&quot;*&quot;,&quot;x&quot;]))
  2. console.log(
  3. JSON.stringify(path),
  4. JSON.stringify(value)
  5. )
  1. [&quot;a&quot;,&quot;b&quot;,&quot;x&quot;] {&quot;y&quot;:1,&quot;z&quot;:2}
  2. [&quot;a&quot;,&quot;c&quot;,&quot;x&quot;] {&quot;y&quot;:4}
  3. [&quot;a&quot;,&quot;d&quot;,&quot;x&quot;] 6

Search for any path ending in z -

  1. for (const [path, value] of get(data, [&quot;**&quot;,&quot;z&quot;]))
  2. console.log(
  3. JSON.stringify(path),
  4. JSON.stringify(value)
  5. )
  1. [&quot;a&quot;,&quot;b&quot;,&quot;x&quot;,&quot;z&quot;] 2
  2. [&quot;a&quot;,&quot;b&quot;,&quot;y&quot;,&quot;z&quot;] 3
  3. [&quot;a&quot;,&quot;c&quot;,&quot;y&quot;,&quot;z&quot;] 5
  4. [&quot;b&quot;,&quot;c&quot;,&quot;z&quot;] 7

Get full path a, c, x, y -

  1. for (const [path, value] of get(data, [&quot;a&quot;,&quot;c&quot;,&quot;x&quot;,&quot;y&quot;]))
  2. console.log(
  3. JSON.stringify(path),
  4. JSON.stringify(value)
  5. )
  1. [&quot;a&quot;,&quot;c&quot;,&quot;x&quot;,&quot;y&quot;] 4

Make complex patterns -

  1. for (const [path, value] of get(data, [&quot;*&quot;,&quot;b&quot;,&quot;**&quot;,&quot;y&quot;]))
  2. console.log(
  3. JSON.stringify(path),
  4. JSON.stringify(value)
  5. )
  1. [&quot;a&quot;,&quot;b&quot;,&quot;x&quot;,&quot;y&quot;] 1
  2. [&quot;a&quot;,&quot;b&quot;,&quot;y&quot;] {&quot;z&quot;:3}

Get non-existent path -

  1. for (const [path, value] of get(data, [&quot;x&quot;,&quot;y&quot;,&quot;z&quot;]))
  2. console.log(
  3. JSON.stringify(path),
  4. JSON.stringify(value)
  5. )
  1. // &lt;empty result&gt;

Verify the results below in your own browser -

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

  1. function *get(t, path) {
  2. function *loop(t, path, match, wild) {
  3. if (path.length === 0)
  4. yield [match, t]
  5. else if (path[0] === &quot;**&quot;)
  6. yield *loop(t, path.slice(1), match, true)
  7. else if (Object(t) === t)
  8. for (const k of Object.keys(t))
  9. if (path[0] === &quot;*&quot; || path[0] === k)
  10. yield *loop(t[k], path.slice(1), [...match, k], false)
  11. else if (wild)
  12. yield *loop(t[k], path, [...match, k], true)
  13. }
  14. yield *loop(t, path, [], false)
  15. }
  16. const data = {
  17. a: {
  18. b: {
  19. x: {y:1, z:2},
  20. y: {z:3},
  21. },
  22. c: {
  23. x: {y:4},
  24. y: {z:5},
  25. },
  26. d: {x:6},
  27. },
  28. b: {c: {z:7}}
  29. }
  30. for (const [path, value] of get(data, [&quot;a&quot;,&quot;*&quot;,&quot;x&quot;]))
  31. console.log(
  32. JSON.stringify(path),
  33. JSON.stringify(value)
  34. )
  35. for (const [path, value] of get(data, [&quot;**&quot;,&quot;z&quot;]))
  36. console.log(
  37. JSON.stringify(path),
  38. JSON.stringify(value)
  39. )
  40. for (const [path, value] of get(data, [&quot;a&quot;,&quot;c&quot;,&quot;x&quot;,&quot;y&quot;]))
  41. console.log(
  42. JSON.stringify(path),
  43. JSON.stringify(value)
  44. )
  45. for (const [path, value] of get(data, [&quot;x&quot;,&quot;y&quot;,&quot;z&quot;]))
  46. console.log(
  47. JSON.stringify(path),
  48. JSON.stringify(value)
  49. )

<!-- language: lang-css -->

  1. .as-console-wrapper { min-height: 100%; top: 0; }

<!-- end snippet -->

sans generators

Here's the same solution without using generators. The interface is identical however it always returns an array instead of an iterator -

  1. function get(t, path) {
  2. const loop = (t, path, match, wild) =&gt;
  3. path.length === 0
  4. ? [[match, t]]
  5. : path[0] === &quot;**&quot;
  6. ? loop(t, path.slice (1), match, true)
  7. : Object(t) === t
  8. ? Object.keys(t).flatMap(k =&gt;
  9. path[0] === &quot;*&quot; || path[0] === k
  10. ? loop(t[k], path.slice (1), [...match, k], false)
  11. : wild
  12. ? loop(t[k], path, [...match, k], true)
  13. : []
  14. )
  15. : []
  16. return loop(t, path, [], false)
  17. }

huangapple
  • 本文由 发表于 2023年6月8日 23:00:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/76433185.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定