Ramda:过滤具有关联值的数组

Ramda: Filtering through arrays with associated value

这是我的初始数据集:

arr1 = [{
      url: ['https://example.com/A.jpg?', 'https://example.com/B.jpg?', 'https://example.com/C.jpg?'], 
      width: ['w=300', 'w=400', 'w=500'], 
      type: [-1, 1, 2]
     }];

通过使用 type: n => n > 0 过滤并将结果传递给 arr1,我想使用 Ramda 生成 arr2。如果过滤结果排除第 n 个值,则另一个数组中的第 n 个值也被排除。

arr2 = [{
      url: ['https://example.com/B.jpg?', 'https://example.com/C.jpg?'], 
      width: ['w=400', 'w=500'], 
      type: [1, 2]
     }];

我尝试了下面的代码,但没有用...

const isgt0 =  n => n > 0 ;

const arr2 = R.applySpec({
url : arr1,
width : arr1,
type :  R.filter(isgt0),
});

console.log(arr2(arr1));

一旦我得到想要的对象,我打算 R.transpose 数组生成一个 URL 像:[https://example.com/B.jpg?w=400, https://example.com/C.jpg?w=500]

这可能有点帮助

const gte1 = R.filter(R.gte(R.__, 1));

const fn = R.map(
  R.evolve({
    type: gte1,
  }),
);


// =====

const data = [
  {
    type: [-1, 1, 2],
    width: ['w=300', 'w=400', 'w=500'],
    url: [
      'https://example.com/A.jpg?', 
      'https://example.com/B.jpg?', 
      'https://example.com/C.jpg?',
    ],
  }
];

console.log(
  fn(data),
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js" integrity="sha512-rZHvUXcc1zWKsxm7rJ8lVQuIr1oOmm7cShlvpV0gWf0RvbcJN6x96al/Rp2L2BI4a4ZkT2/YfVe/8YvB2UHzQw==" crossorigin="anonymous"></script>

主要步骤是:

获取 R.props 值的数组:

  • [-1, 1, 2]
  • ['w=300', 'w=400', 'w=500']
  • ['https://example.com/A.jpg?', 'https://example.com/B.jpg?', 'https://example.com/C.jpg?']

将它们转置为具有相同索引的项目数组:

  • [-1, 'w=300', 'https://example.com/A.jpg?']
  • [1, 'w=400', 'https://example.com/B.jpg?']
  • [1, 'w=500', 'https://example.com/C.jpg?']

按索引0过滤(原来的type),转置回去,然后使用R.applySpec.

重建对象

const { pipe, props, transpose, filter, propSatisfies, gt, __, tranpose, applySpec, nth, map } = R

const filterProps = pipe(
  props(['type', 'width', 'url']), // get an array of property
  transpose, // convert to arrays of all property values with the same index
  filter(propSatisfies(gt(__, 0), 0)), // filter by the type (index 0)
  transpose, // convert back to arrays of each type
  applySpec({ // reconstruct the object
    type: nth(0),
    width: nth(1),
    url: nth(2),
  })
)

const data = [
  {
    type: [-1, 1, 2],
    width: ['w=300', 'w=400', 'w=500'],
    url: [
      'https://example.com/A.jpg?', 
      'https://example.com/B.jpg?', 
      'https://example.com/C.jpg?',
    ],
  }
]

const result = map(filterProps, data)

console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.js" integrity="sha512-3sdB9mAxNh2MIo6YkY05uY1qjkywAlDfCf5u1cSotv6k9CZUSyHVf4BJSpTYgla+YHLaHG8LUpqV7MHctlYzlw==" crossorigin="anonymous"></script>

另一种更普遍地考虑它的方法是使用配置对象进行过滤,该配置对象包含用于申请各种属性的测试。这里只有type,其他的想起来也很容易

我对这个问题的解决方案是用这个对象配置的:

{
    type: n => n > 0
}

这个解决方案使用了许多 Ramda 函数,但也使用 Array.prototype.filter 来访问 filter 的索引参数。我们可以选择 R.addIndex,但我只会在试图使它成为 point-free 时才费心,这在这里似乎不值得。它可能是这样的:

const filterOnProps = (config) => (obj) => {
  const test = allPass (map(([k, v]) => (i) => v (obj [k] [i]), toPairs (config)))
  const indices = filter (test) (range (0, values (obj) [0] .length))
  return map(a => a .filter ((_, i) => contains (i, indices)), obj)
}

const transform =  map (filterOnProps ({type: n => n > 0}))

const arr1 = [{url: ['https://example.com/A.jpg?', 'https://example.com/B.jpg?', 'https://example.com/C.jpg?'], width: ['w=300', 'w=400', 'w=500'], type: [-1, 1, 2]}]

console .log (transform (arr1))
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js"></script>
<script> const {allPass, map, toPairs, filter, range, values, contains} = R    </script>

obj 范围内,我们创建 test,这在某种程度上等同于

allPass([
    i => obj['type'][i] > 0
])

如果我们在原始配置对象中有更多条件,它们也会在此列表中。

然后我们过滤索引,看看记录在哪些索引上通过了这个测试。

最后我们映射我们的对象,过滤每个数组以仅保留索引在列表中的数组。


虽然这应该可行,而且相当通用,但它表明您的数据结构存在问题。我建议您尽可能避免结构依赖于共享索引的情况。在我看来,唯一合理的用途是用于相对紧凑的序列化格式。在反序列化时,我会立即将其重新组合成更有用的东西,比如

const data = [
    {url: 'https://example.com/A.jpg?', width: 'w=300', type: -1}, 
    {url: 'https://example.com/B.jpg?', width: 'w=400', type: 1},
    {url: 'https://example.com/C.jpg?', width: 'w=500', type: 2}
]

这种结构更容易使用。例如,如果您从这个结构开始,data.filter(({type}) => type > 0) 将等同于上面的工作。