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.entriesArray.prototype.mapObject.fromEntries 的舞蹈在普通 JS 中编写 mapObject 函数就足够容易了。

我现在没有时间玩这个,但我认为在这里使用 EitherResult 实现可能值得研究。这可能会导致更合乎逻辑的代码。