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)
将等同于上面的工作。
这是我的初始数据集:
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)
将等同于上面的工作。