【问题标题】:Pipes, ramda with dynamic arguments管道,带有动态参数的 ramda
【发布时间】:2019-10-04 18:49:11
【问题描述】:
cons columnDefs = [
   {
     label: 'The_First_Name',
     value: getProp,
     args: ['firstName'] // different number of arguments depending on function
   },
   {
     label: 'City',
     value: getNestedProperty,
     args: ['location', 'city'] 
   }
]

const data = [
  {
     firstName: 'Joe',
     lastName: 'Smith',
     location: {
       city: 'London'
     }
  },
   {
     firstName: 'Anna',
     lastName: 'Andersson',
     location: {
       city: 'Stockholm'
     }
  }
]

const getProp = (object, key) => R.prop(key, object);

const getNestedProperty = (obj, args) => R.path(..args, obj);

Ramda 管道映射数据:

const tableBuilder = R.pipe(R.map); // some ramda functions in here

const rows = tableBuilder(data, columnDefs);

想要的输出:

rows output:

[
   {
      The_First_Name: 'Joe',
      city: 'London'
   },
   {
      The_First_Name: 'Anna',
      city: 'Stockholm'
   }
]

每一行的键是columnDefs 中的label 属性。该值是从value 属性中的Ramda 函数以及args 属性中定义的参数获取的。

https://plnkr.co/edit/rOGh4zkyOEF24TLaCZ4e?p=preview

完全卡住了。这甚至可能与 Ramda 相关吗?还是用纯 JavaScript 更好?

【问题讨论】:

  • rows 和 columnDefs 有什么关系,你能解释一下吗?
  • @KOTIOS。我更新了变量名称,使其更加清晰。
  • 您的动态变量不清楚,您能否发布至少 2 个正确的输入,其中包含动态变量中的值及其对应的输出
  • @KOTIOS。我又添加了一个示例。

标签: javascript ramda.js


【解决方案1】:

您可以使用applySpec 从另一个对象创建一个对象:

const obj = applySpec({
  The_First_Name: prop('firstName'),
  city: path(['location', 'city'])
})

obj({
  firstName: 'Joe',
  lastName: 'Smith',
  location: {
     city: 'London'
   }
});
//=> {"The_First_Name": "Joe", "city": "London"}

然后你可以使用该函数来映射你的数组:

const data = [
  {
     firstName: 'Joe',
     lastName: 'Smith',
     location: {
       city: 'London'
     }
  },
   {
     firstName: 'Anna',
     lastName: 'Andersson',
     location: {
       city: 'Stockholm'
     }
  }
];

const obj = applySpec({
  The_First_Name: prop('firstName'),
  city: path(['location', 'city'])
})

console.log(

  map(obj, data)

);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>
<script>const {applySpec, prop, path, map} = R;</script>

这是您将columnDefs 转换为可与applySpec 一起使用的对象的方式:

const spec = def => ({[def.label]: apply(def.value, def.args)});
const specs = compose(mergeAll, map(spec));

const columnDefs = [
   {
     label: 'The_First_Name',
     value: prop,
     args: ['firstName'] // different number of arguments depending on function
   },
   {
     label: 'City',
     value: path,
     args: [['location', 'city']]
   }
]

const data = [
  {
     firstName: 'Joe',
     lastName: 'Smith',
     location: {
       city: 'London'
     }
  },
   {
     firstName: 'Anna',
     lastName: 'Andersson',
     location: {
       city: 'Stockholm'
     }
  }
]

const spec = def => ({[def.label]: apply(def.value, def.args)});
const specs = compose(mergeAll, map(spec));

console.log(

  map(applySpec(specs(columnDefs)), data)

);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>
<script>const {apply, compose, mergeAll, map, prop, path, applySpec} = R;</script>

【讨论】:

  • columnDefs 应该是与数据一起构建输出的参数。 The_First_Name 和 city 应该从 columnDefs 中的 label 属性中获取。
  • 您应该能够从您的columnDefs 数组生成传递给applySpec 的对象。
  • 非常好。但是请参阅我对prop 问题的回答。
【解决方案2】:

以下应该有效:

const tableBuilder = (objs, spec) => objs .map (
  obj => Object .assign ( ...spec.map (
    ( {label, value, args} ) => ( { [label]: value (obj, args) } )
  ))
)

const getProp = (object, key) => R.prop (key, object);

const getNestedProperty = (obj, args) => R.path (args, obj);

const columnDefs = [
   {label: 'The_First_Name', value: getProp, args: ['firstName']},
   {label: 'City', value: getNestedProperty, args: ['location', 'city']}
]

const data = [
  {firstName: 'Joe', lastName: 'Smith', location: {city: 'London'}},
  {firstName: 'Anna', lastName: 'Andersson', location: {city: 'Stockholm'}}
]

console .log (
  tableBuilder (data, columnDefs)
)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script> <script>
const {prop, path} = R                                                         </script>

但它的工作主要是偶然的。您可能需要重新考虑一下您的函数是如何定义的。

这是调用 prop (['firstName'], obj) 的等价物,它恰好像 prop ('firstName', obj) 一样工作,但原因与 'foo' + ['bar'] 产生 'foobar' 的原因相同。这是一个你可能不应该依赖的巧合。

问题是你想统一处理接受单个参数的函数和接受参数数组的函数。这是个问题。您可能需要保持一致。

虽然您可以为此编写 Ramda 注释,但我不确定它是否更具可读性。也许用mergeAll (spec.map ( 替换Object .assign (...spec.map ( 会更干净。如果您不介意更改参数顺序,则可能需要进行更多清理。但这已经相当可读了。

更新

@customcommander 的回答让我确信 Ramda 确实可以在这里增加一些价值。这要求您愿意为您的 value 函数交换参数顺序,并愿意将其称为完全柯里化函数 (tableBuilder (columnDefs) (data)),但这确实会产生一些非常好的代码。

这主要是customcommander的工作,但我对其进行了一些调整以使功能更具可读性:

const spec = ({label, value, args}) => ({[label]: value(args)})

const tableBuilder = pipe(
  map(spec),
  mergeAll,
  applySpec,
  map
)

const columnDefs = [
   {label: 'The_First_Name', value: prop, args: ['firstName']},
   {label: 'City', value: path, args: ['location', 'city']}
]

const data = [
  {firstName: 'Joe', lastName: 'Smith', location: {city: 'London'}},
  {firstName: 'Anna', lastName: 'Andersson', location: {city: 'Stockholm'}}
]


console .log (
  tableBuilder (columnDefs) (data)
)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script><script>
const {prop, path, pipe, map, mergeAll, applySpec} = R                        </script>

这与之前prop 的问题相同,但请注意,您可以在此处将其替换为path 而不会造成伤害。要点是所有value 函数都应该具有相同的输入(值数组和要处理的对象)。如果有,那么这应该适用于其中任何一个。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-27
    • 1970-01-01
    • 2020-02-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多