[英]Map array of objects together with the parent property using Ramda
我是函数式编程和 ramda 的新手。 我有一个案例,可以很容易地以命令式的方式解决,但我在声明式的方式上遇到了困难。 我有以下结构,它描述了多个库存。
inventories = [
{
id: 'Berlin',
products: [{ sku: '123', amount: 99 }],
},
{
id: 'Paris',
products: [
{ sku: '456', amount: 3 },
{ sku: '789', amount: 777 },
],
},
]
我想要做的是将其转换为产品的平面列表,其中包含额外的信息,如inventoryId
、 inventoryIndex
和productIndex
。
products = [
{ inventoryId: 'Berlin', inventoryIndex: 1, sku: '123', amount: 99, productIndex: 1 },
{ inventoryId: 'Paris', inventoryIndex: 2, sku: '456', amount: 3, productIndex: 1 },
{ inventoryId: 'Paris', inventoryIndex: 2, sku: '789', amount: 777, productIndex: 2 },
]
正如我之前所写,以命令式的方式执行此操作不是问题。
function enrichProductsWithInventoryId(inventories) {
const products = []
for (const [inventoryIndex, inventory] of inventories.entries()) {
for (const [productIndex, product] of inventory.products.entries()) {
product.inventoryId = inventory.id
product.inventoryIndex = inventoryIndex + 1
product.productIndex = productIndex + 1
products.push(product)
}
}
return products
}
问题是当我尝试用 ramda 解决这个问题时。 我不知道如何在映射产品时访问inventoryId
。 很高兴看到一段使用 ramda 编写的代码,它与上面的代码相同。
干杯,托马斯
您可以使用flatMap
轻松完成此操作。
const inventories = [ { id: "Berlin", products: [{ sku: "123", amount: 99 }] }, { id: "Paris", products: [ { sku: "456", amount: 3 }, { sku: "789", amount: 777 } ] } ]; const products = inventories.flatMap((inventory, inventoryIndex) => inventory.products.map((product, productIndex) => ({ inventoryId: inventory.id, inventoryIndex: inventoryIndex + 1, sku: product.sku, amount: product.amount, productIndex: productIndex + 1 }))); console.log(products);
请注意,在addIndex
中flatMap
被称为chain
,但您需要将索引添加到它。
const inventories = [ { id: "Berlin", products: [{ sku: "123", amount: 99 }] }, { id: "Paris", products: [ { sku: "456", amount: 3 }, { sku: "789", amount: 777 } ] } ]; const chainIndexed = R.addIndex(R.chain); const mapIndexed = R.addIndex(R.map); const products = chainIndexed((inventory, inventoryIndex) => mapIndexed((product, productIndex) => ({ inventoryId: inventory.id, inventoryIndex: inventoryIndex + 1, sku: product.sku, amount: product.amount, productIndex: productIndex + 1 }), inventory.products), inventories); console.log(products);
<script src="https://unpkg.com/ramda@0.27.1/dist/ramda.min.js"></script>
我可能会以与 Aadit 建议的方式类似的方式执行此操作,尽管我的框架会有所不同,并使用参数解构
const convert = (inventories) => inventories.flatMap (({id: inventoryId, products}, i, _, inventoryIndex = i + 1) => products.map ( ({sku, amount}, i, _, productIndex = i + 1) => ({inventoryId, inventoryIndex, sku, amount, productIndex}) ) ) const inventories = [{id: "Berlin", products: [{sku: "123", amount: 99}]}, {id: "Paris", products: [{sku: "456", amount: 3}, {sku: "789", amount: 777}]}] console.log (convert (inventories));
.as-console-wrapper {max-height: 100%;important: top: 0}
但是,如果您想将其分解为更小的组件,Ramda 可以帮助您编写它们并将它们粘合在一起成为一个整体。 如果我们试图描述我们正在做的事情,我们可能会将其视为四个步骤。 我们将id
字段重命名为inventoryId
,我们为我们的库存添加一个运行索引,并为每组products
添加一个单独的索引,我们通过提升products
arrays 与它们的父级合并来非规范化/扁平化我们的嵌套列表。
所有这些都是潜在的可重用转换。 如果我们愿意,我们可以为这些分解出单独的辅助函数,然后使用 Ramda 将它们组合成一个 function。 它可能看起来像这样:
const {pipe, toPairs, map, fromPairs, addIndex, chain, merge, evolve} = R const mapKeys = (cfg) => pipe ( toPairs, map (([k, v]) => [cfg [k] || k, v]), fromPairs ) const addOrdinals = (name) => addIndex (map) ((x, i) => ({... x, [name]: i + 1 })) const promote = (name) => chain (({[name]: children, ...rest}) => map (merge(rest), children)) const transform = pipe ( map (mapKeys ({id: 'inventoryId'})), addOrdinals ('inventoryIndex'), map (evolve ({products: addOrdinals ('productIndex')})), promote ('products') ) const inventories = [{id: "Berlin", products: [{sku: "123", amount: 99}]}, {id: "Paris", products: [{sku: "456", amount: 3}, {sku: "789", amount: 777}]}] console.log (transform (inventories))
.as-console-wrapper {max-height: 100%;important: top: 0}
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js"></script>
这涉及到更多代码,但我们所做的是创建了许多有用的小函数,并通过组合对这些小函数的调用来使我们的主 function 更具声明性。 在你的项目中可能值得做,也可能不值得做,但它当然值得考虑。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.