Ramda:拒绝谓词数组
Ramda: Rejects from predicate array
https://jsbin.com/ziyufuxacu/edit?html,js,console,output
如何报告谓词数组的拒绝并且仅报告第一个拒绝
这是我的尝试,但我觉得有 ramda 函数可以使它更通用,例如,如果我有 10 个谓词
var selected = [{
Label: "a",
Invalid: false,
Deleted: true
}, {
Label: "b",
Invalid: false,
Deleted: false
}, {
Label: "c",
Invalid: true,
Deleted: false
}];
var canEditPredicates = [
R.propEq("Deleted", false),
R.propEq("Invalid", false),
R.propEq("Label", "c")
];
var deleted = R.reject(canEditPredicates[0], selected);
var invalid = R.reject(canEditPredicates[1], R.without(deleted, selected));
var names = R.reject(canEditPredicates[2], R.without(deleted, R.without(invalid, selected)));
var rv = "The following items are bad:";
if (deleted.length) {
rv += "\r\nDeleted items: " + R.join(", ")(R.pluck("Label")(deleted));
}
if (invalid.length) {
rv += "\r\ninvalid items: " + R.join(", ")(R.pluck("Label")(invalid));
}
if (names.length) {
rv += "\r\nnames items: " + R.join(", ")(R.pluck("Label")(names));
}
console.log(rv);
输出
The following items are bad:
Deleted items: a
invalid items: c
names items: b
要了解项目被拒绝的原因(谓词的索引),您可以使用带有谓词数组的翻转 R.findIndex。应该补充谓词,因为我们希望 true
用于失败的答案。传递给 fins 的值应该用 R.applyTo 包装,因为 R.find 需要谓词函数。
然后您可以映射项目数组,传递值,并获取每个失败项目的谓词索引。如果该项目通过了所有检查(未通过补充),您将获得 -1
而不是谓词索引。
const { propEq, map, pipe, applyTo, flip, findIndex, complement } = R;
const canEditPredicates = [
propEq("Deleted", false),
propEq("Invalid", false),
propEq("Label", "c")
];
const findFailedPredicateIndex = pipe(applyTo, flip(findIndex)(map(complement, canEditPredicates)));
const findFailed = map(findFailedPredicateIndex);
const selected = [{"Label":"a","Invalid":false,"Deleted":true},{"Label":"b","Invalid":false,"Deleted":false},{"Label":"c","Invalid":true,"Deleted":false},{"Label":"c","Invalid":false,"Deleted":false}];
const result = findFailed(selected);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js" integrity="sha512-rZHvUXcc1zWKsxm7rJ8lVQuIr1oOmm7cShlvpV0gWf0RvbcJN6x96al/Rp2L2BI4a4ZkT2/YfVe/8YvB2UHzQw==" crossorigin="anonymous"></script>
此版本对您的输入进行了一些改动。他们可能没有道理。但在我看来,它们构成了一个更合乎逻辑的系统。如果更改过大,请随意忽略。
这样做最大的作用就是颠倒了谓词的意义。这些版本现在列为 cannotEditPredicates
而不是 canEditPredicates
。这使我们可以更简单地编写它们。例如,Deleted
谓词可以只是 R.prop("Deleted")
而不是 R.prop('Deleted', false)
.
我还以不同方式捆绑它们,以便我们更清楚地捕获失败结果。它们不是数组,而是收集在一个对象中,该对象由您在预期输出中使用的名称键入。
这给了我们一个类似
的输出结构
{
Deleted: ["a", "e"],
invalid: ["c"],
name: ["b"]
}
但我们可以简单地更改它以包含整个对象而不是标签。
这是它的样子:
const rejectPreds = (selected, cannotEditPredicates) => R.reduce (
(output, item) => {
const rec = R.find (([k, v]) => v (item))(R.toPairs (cannotEditPredicates))
return rec == undefined
? output
: {...output, [rec [0]]: [...output [rec [0]], item .Label]}
},
R.map (v => []) (cannotEditPredicates),
selected
)
const selected = [
{Label: "a", Invalid: false, Deleted: true},
{Label: "b", Invalid: false, Deleted: false},
{Label: "c", Invalid: true, Deleted: false},
{Label: "d", Invalid: false, Deleted: false},
{Label: "e", Invalid: false, Deleted: true}
];
const cannotEditPredicates = {
Deleted: R.prop("Deleted"),
invalid: R.prop("Invalid"),
name: R.propEq("Label", "b")
}
const rejected = rejectPreds (selected, cannotEditPredicates)
console .log (rejected)
console .log (`The following items are bad:
${Object .entries (rejected) .map (([n, v]) => `${n}: [${[...v]}]`) .join ('\n')}
`)
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js"></script>
请注意,尽管这使用了各种 Ramda 函数,但几乎所有函数都可以轻松替换为 Array.prototype
上的版本。唯一比较困难的地方是 map
调用,Ramda 以相当明显的方式在对象上运行。如果需要的话,使用 Object.entries
、Array.prototype.map
和 Object.fromEntries
的舞蹈在普通 JS 中编写 mapObject
函数就足够容易了。
我现在没有时间玩这个,但我认为在这里使用 Either
或 Result
实现可能值得研究。这可能会导致更合乎逻辑的代码。
https://jsbin.com/ziyufuxacu/edit?html,js,console,output
如何报告谓词数组的拒绝并且仅报告第一个拒绝
这是我的尝试,但我觉得有 ramda 函数可以使它更通用,例如,如果我有 10 个谓词
var selected = [{
Label: "a",
Invalid: false,
Deleted: true
}, {
Label: "b",
Invalid: false,
Deleted: false
}, {
Label: "c",
Invalid: true,
Deleted: false
}];
var canEditPredicates = [
R.propEq("Deleted", false),
R.propEq("Invalid", false),
R.propEq("Label", "c")
];
var deleted = R.reject(canEditPredicates[0], selected);
var invalid = R.reject(canEditPredicates[1], R.without(deleted, selected));
var names = R.reject(canEditPredicates[2], R.without(deleted, R.without(invalid, selected)));
var rv = "The following items are bad:";
if (deleted.length) {
rv += "\r\nDeleted items: " + R.join(", ")(R.pluck("Label")(deleted));
}
if (invalid.length) {
rv += "\r\ninvalid items: " + R.join(", ")(R.pluck("Label")(invalid));
}
if (names.length) {
rv += "\r\nnames items: " + R.join(", ")(R.pluck("Label")(names));
}
console.log(rv);
输出
The following items are bad:
Deleted items: a
invalid items: c
names items: b
要了解项目被拒绝的原因(谓词的索引),您可以使用带有谓词数组的翻转 R.findIndex。应该补充谓词,因为我们希望 true
用于失败的答案。传递给 fins 的值应该用 R.applyTo 包装,因为 R.find 需要谓词函数。
然后您可以映射项目数组,传递值,并获取每个失败项目的谓词索引。如果该项目通过了所有检查(未通过补充),您将获得 -1
而不是谓词索引。
const { propEq, map, pipe, applyTo, flip, findIndex, complement } = R;
const canEditPredicates = [
propEq("Deleted", false),
propEq("Invalid", false),
propEq("Label", "c")
];
const findFailedPredicateIndex = pipe(applyTo, flip(findIndex)(map(complement, canEditPredicates)));
const findFailed = map(findFailedPredicateIndex);
const selected = [{"Label":"a","Invalid":false,"Deleted":true},{"Label":"b","Invalid":false,"Deleted":false},{"Label":"c","Invalid":true,"Deleted":false},{"Label":"c","Invalid":false,"Deleted":false}];
const result = findFailed(selected);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js" integrity="sha512-rZHvUXcc1zWKsxm7rJ8lVQuIr1oOmm7cShlvpV0gWf0RvbcJN6x96al/Rp2L2BI4a4ZkT2/YfVe/8YvB2UHzQw==" crossorigin="anonymous"></script>
此版本对您的输入进行了一些改动。他们可能没有道理。但在我看来,它们构成了一个更合乎逻辑的系统。如果更改过大,请随意忽略。
这样做最大的作用就是颠倒了谓词的意义。这些版本现在列为 cannotEditPredicates
而不是 canEditPredicates
。这使我们可以更简单地编写它们。例如,Deleted
谓词可以只是 R.prop("Deleted")
而不是 R.prop('Deleted', false)
.
我还以不同方式捆绑它们,以便我们更清楚地捕获失败结果。它们不是数组,而是收集在一个对象中,该对象由您在预期输出中使用的名称键入。
这给了我们一个类似
的输出结构{
Deleted: ["a", "e"],
invalid: ["c"],
name: ["b"]
}
但我们可以简单地更改它以包含整个对象而不是标签。
这是它的样子:
const rejectPreds = (selected, cannotEditPredicates) => R.reduce (
(output, item) => {
const rec = R.find (([k, v]) => v (item))(R.toPairs (cannotEditPredicates))
return rec == undefined
? output
: {...output, [rec [0]]: [...output [rec [0]], item .Label]}
},
R.map (v => []) (cannotEditPredicates),
selected
)
const selected = [
{Label: "a", Invalid: false, Deleted: true},
{Label: "b", Invalid: false, Deleted: false},
{Label: "c", Invalid: true, Deleted: false},
{Label: "d", Invalid: false, Deleted: false},
{Label: "e", Invalid: false, Deleted: true}
];
const cannotEditPredicates = {
Deleted: R.prop("Deleted"),
invalid: R.prop("Invalid"),
name: R.propEq("Label", "b")
}
const rejected = rejectPreds (selected, cannotEditPredicates)
console .log (rejected)
console .log (`The following items are bad:
${Object .entries (rejected) .map (([n, v]) => `${n}: [${[...v]}]`) .join ('\n')}
`)
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js"></script>
请注意,尽管这使用了各种 Ramda 函数,但几乎所有函数都可以轻松替换为 Array.prototype
上的版本。唯一比较困难的地方是 map
调用,Ramda 以相当明显的方式在对象上运行。如果需要的话,使用 Object.entries
、Array.prototype.map
和 Object.fromEntries
的舞蹈在普通 JS 中编写 mapObject
函数就足够容易了。
我现在没有时间玩这个,但我认为在这里使用 Either
或 Result
实现可能值得研究。这可能会导致更合乎逻辑的代码。