【问题标题】:Group arrays by parent ids object Ramda按父 ID 对象 Ramda 对数组进行分组
【发布时间】:2020-02-29 02:28:27
【问题描述】:

需要 Ramda 社区的帮助...我有一个对象数组,我需要按“chapter_id”排序,排序后,只需删除“chapter_id”:

const stuff = [
  { id: 1, title: "hello world", chapter_id: "4321" },
  { id: 2, title: "new title", chapter_id: "21" },
  { id: 3, title: "...", chapter_id: "33" },
  { id: 4, title: "huh!?", chapter_id: "14" },
  { id: 5, title: "From Earth", chapter_id: "11" },
  { id: 6, title: "alien", chapter_id: "11" },
  { id: 7, title: "Saturn", chapter_id: "11" },
  { id: 8, title: "Mars:/", chapter_id: "21" },
  { id: 9, title: "damn", chapter_id: "3" },
  { id: 10, title: "test", chapter_id: "11" },
  { id: 11, title: "ramda heeeelp", chapter_id: "31" },
  { id: 12, title: "hello?", chapter_id: "21" }
]

结果我想得到这个对象:

{
  "3": [
    {
      "id": "9",
      "title": "damn"
    }
  ],
  "11": [
    {
      "id": "5",
      "title": "From Earth"
    },
    {
      "id": "6",
      "title": "alien"
    },
    {
      "id": "7",
      "title": "Saturn"
    },
    {
      "id": "10",
      "title": "test"
    }
  ],
  "14": [
    {
      "id": "4",
      "title": "huh!?"
    }
  ],
  "21": [
    {
      "id": "2",
      "title": "new title"
    },
    {
      "id": "8",
      "title": "Mars:/"
    },
    {
      "id": "12",
      "title": "hello?"
    }
  ],
  "31": [
    {
      "id": "11",
      "title": "ramda heeeelp"
    }
  ],
  "33": [
    {
      "id": "3",
      "title": "..."
    }
  ],
  "4321": [
    {
      "id": "1",
      "title": "hello world"
    }
  ]
}

我是如何解决这个问题的:

let object = {};

map(({ chapter_id }) => {
  const composed = compose(
    map(evolve({ id: toString })), //here id is converted to a string
    filter(c => c.chapter_id === chapter_id),
  );
  object[chapter_id] = composed(stuff)
}, stuff);

我的结果:

{
  "3": [
    {
      "id": "9",
      "title": "damn",
      "chapter_id": "3" //Dissoc this
    }
  ],
  "11": [
    {
      "id": "5",
      "title": "From Earth",
      "chapter_id": "11" //dissoc this
    },
    {
      "id": "6",
      "title": "alien",
      "chapter_id": "11"  //and this
    },
    {
      "id": "7",
      "title": "Saturn",
      "chapter_id": "11" //and this
    },
    {
      "id": "10",
      "title": "test",
      "chapter_id": "11" //and this
    }
  ],
  "14": [
    {
      "id": "4",
      "title": "huh!?",
      "chapter_id": "14" //and this
    }
  ],
  "21": [
    {
      "id": "2",
      "title": "new title",
      "chapter_id": "21" //and this
    },
    {
      "id": "8",
      "title": "Mars:/",
      "chapter_id": "21" //and this
    },
    {
      "id": "12",
      "title": "hello?",
      "chapter_id": "21" //and this
    }
  ],
  "31": [
    {
      "id": "11",
      "title": "ramda heeeelp",
      "chapter_id": "31" //and this!!!!!!
    }
  ],
  "33": [
    {
      "id": "3",
      "title": "...",
      "chapter_id": "33" //and this..
    }
  ],
  "4321": [
    {
      "id": "1",
      "title": "hello world",
      "chapter_id": "4321" //and this:(
    }
  ]
}

它有效,但我无法从每个对象中分离“chapter_id”,有人知道如何解决这个问题吗? :Δ

【问题讨论】:

    标签: javascript functional-programming ramda.js


    【解决方案1】:

    正如 Ori Drori 所说,这可能是 Ramda 方法:

    const transform = pipe (
      groupBy(prop('chapter_id')),
      map(map(dissoc('chapter_id'))),
    )
    

    但是,如果您确实需要对键进行排序,正如您的回答所暗示的那样,则需要更多的处理。你可以试试这样的:

    const transform = pipe (
      groupBy(prop('chapter_id')),
      map(map(dissoc('chapter_id'))),
      toPairs,
      sortBy(pipe(head, Number)),
      fromPairs
    )
    
    const stuff = [{id: 1, title: "hello world", chapter_id: "4321"}, {id: 2, title: "new title", chapter_id: "21"}, {id: 3, title: "...", chapter_id: "33"}, {id: 4, title: "huh!?", chapter_id: "14"}, {id: 5, title: "From Earth", chapter_id: "11"}, {id: 6, title: "alien", chapter_id: "11"}, {id: 7, title: "Saturn", chapter_id: "11"}, {id: 8, title: "Mars: /", chapter_id: "21"}, {id: 9, title: "damn", chapter_id: "3"}, {id: 10, title: "test", chapter_id: "11"}, {id: 11, title: "ramda heeeelp", chapter_id: "31"}, {id: 12, title: "hello?", chapter_id: "21"}]
    
    console.log (
      transform (stuff)
    )
    <script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
    <script> const {pipe, groupBy, prop, map, dissoc, toPairs, sortBy, head, fromPairs} = R </script>

    该排序线可以用多种方式编写。也许

    sort(lift(subtract)(head, head)),
    

    或者只是

    sort(([a], [b]) => a - b),
    

    显然,如果您愿意,您可以像这样提取sortByKeys 函数:

    const sortByKeys = (fn) => pipe(toPairs, sortBy(fn), fromPairs)
    
    

    sortByKeys 不太可能包含在 Ramda 中,它更倾向于将对象视为名称-值对的无序集合。但它可以轻松放入您自己的帮助程序库中。

    【讨论】:

    • 由于objects's traversal order of integer indices in ES6,不需要使用数字键对对象进行排序。删除排序代码,结果不会改变。然而,它会影响非整数索引,因为它们尊重条目的顺序。
    • 嗨斯科特!谢谢你的回答,对我真的很有帮助。我遇到了一个新问题,你能检查一下吗? - stackoverflow.com/q/58683743/9464680
    • @OriDrori:是的,但这只是因为它们是只包含数字的小字符串。如果它们是字符串化的浮点数或纯字符串或几乎其他任何东西,那是行不通的。但是这种技术可以扩展到我们可以排序的任何键。
    【解决方案2】:

    使用 Ramda,您可以按 key 分组,然后映射组,并将 key 从所有对象中分离出来:

    const { pipe, groupBy, prop, map, dissoc } = R;
    
    const fn = key => pipe(
      groupBy(prop(key)), // group by the key
      map(map(dissoc(key))) // remove the key from all objects in all groups
    );
    
    const stuff = [{"id":1,"title":"hello world","chapter_id":"4321"},{"id":2,"title":"new title","chapter_id":"21"},{"id":3,"title":"...","chapter_id":"33"},{"id":4,"title":"huh!?","chapter_id":"14"},{"id":5,"title":"From Earth","chapter_id":"11"},{"id":6,"title":"alien","chapter_id":"11"},{"id":7,"title":"Saturn","chapter_id":"11"},{"id":8,"title":"Mars:/","chapter_id":"21"},{"id":9,"title":"damn","chapter_id":"3"},{"id":10,"title":"test","chapter_id":"11"},{"id":11,"title":"ramda heeeelp","chapter_id":"31"},{"id":12,"title":"hello?","chapter_id":"21"}];
    
    const result = fn('chapter_id')(stuff);
    
    console.log(result);
    &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"&gt;&lt;/script&gt;

    【讨论】:

      【解决方案3】:

      首先,没有正确描述有限任务 :) 你真正想要的(基于 result I want to get 部分)是规范化(或重组)数组对象转换成一个对象,以chapter_id为键,值是stuff数组与chapter_id的关联记录的数组

      在我看来,您的解决方案很酷,而且看起来更实用,但在这种特殊情况下,我可能会优先考虑简单的 reduce 函数,它更具可读性...

      reduce((acc, {chapter_id, ...rest}) => {
        const isInitialized = !!acc[chapter_id];
        if (isInitialized) {
          acc[chapter_id].push(rest); 
        } else {
          acc[chapter_id] = [rest];
        }
        return acc;
      }, {}, stuff);
      

      【讨论】:

        猜你喜欢
        • 2012-12-19
        • 2022-12-16
        • 1970-01-01
        • 2021-10-05
        • 1970-01-01
        • 1970-01-01
        • 2021-10-14
        • 2021-05-05
        相关资源
        最近更新 更多