【问题标题】:How to sort object with ramda js如何使用 ramda js 对对象进行排序
【发布时间】:2019-06-05 22:09:23
【问题描述】:

我想对下面的对象进行排序,

const form = {
A_ALL: {A1_ALL: { A1_ONE: 'Y', A2_TWO: 'Y', A3_THREE: 'Y'}, A2: {A2_FOUR: 'Y', A2_FIVE: 'N', A2_SIX: 'Y'}, A3: 'Y', A4: 'N'},
B_ALL: {B1_ALL: { B1_ONE: 'Y', B1_TWO: 'Y', B1_THREE: 'Y'}, B2: {B2_FOUR: 'Y', B2_FIVE: 'Y', B2_SIX: 'Y'}, B3: 'Y', B4: 'Y'},
C_ALL: {XX: 'Y', YY:'Y'},
D: 'Y',
E: 'N'
}

我正在实现一个带有嵌套复选框的表单,其值可以是“Y”或“N”。我只想捕获“Y”复选框,如果所有子复选框都是“Y”,我想丢弃它们并只获取父复选框。以上是具有所有复选框值的对象。我希望将对象排序为:

{
A_ALL: {A1_ALL: 'Y', A2: {A2_FOUR: 'Y', A2_SIX: 'Y'}, A3: 'Y'},
B_ALL : 'Y',
C: 'Y',
D: 'Y'
}

到目前为止,我的代码如下所示:

const FORM = ({ A1_ALL: { a: 'Y', b: 'Y', c: 'Y' }, B1_ALL: { a: 'Y', b: 'Y', c: 'N' }, C1_ALL: { a: 'Y', b: 'Y', c: 'Y' }, }) 
const eY = equals('Y') 
const isSelected = compose(all(eY), values) 
const groupValue = when(isSelected, always('Y')); 
const formValue = map(groupValue) formValue(FORM) Result is {A1_ALL: "Y", C1_ALL: "Y", B1_ALL: {a: "Y", b: "Y", c: "N"}}

【问题讨论】:

  • 到目前为止你尝试了什么?
  • 我使用 Ramda 实现了以下代码, const FORM = ({ A1_ALL: { a: 'Y', b: 'Y', c: 'Y' }, B1_ALL: { a: ' Y', b: 'Y', c: 'N' }, C1_ALL: { a: 'Y', b: 'Y', c: 'Y' }, }) const eY = equals('Y') const isSelected = compose(all(eY), values) const groupValue = when(isSelected, always('Y')); const formValue = map(groupValue) formValue(FORM) 结果是 {A1_ALL: "Y", C1_ALL: "Y", B1_ALL: {a: "Y", b: "Y", c: "N"}}跨度>
  • 假设你的结果是一个递归包含所有Ys的对象,最终结果不应该只是字符串Y吗?

标签: javascript sorting filtering ramda.js


【解决方案1】:

我有部分解决方案,目前没有时间进行下一步。它实质上会过滤掉任何不是'Y's 的值。然后,您应该能够添加另一个步骤,通过将仅包含 'Y' 值的对象的值递归替换为仅包含 'Y' 的值。

const form = {
      A_ALL: {A1_ALL: { A1_ONE: 'Y', A2_TWO: 'Y', A3_THREE: 'Y'}, A2: {A2_FOUR: 'Y', A2_FIVE: 'N', A2_SIX: 'Y'}, A3: 'Y', A4: 'N'},
      B_ALL: {B1_ALL: { B1_ONE: 'Y', B1_TWO: 'Y', B1_THREE: 'Y'}, B2: {B2_FOUR: 'Y', B2_FIVE: 'Y', B2_SIX: 'Y'}, B3: 'Y', B4: 'Y'},
      C_ALL: {XX: 'Y', YY:'Y'},
      D: 'Y',
      E: 'N'
}

const isObject = s => Object.prototype.toString.call(s) == '[object Object]'
const isArray = s => Object.prototype.toString.call(s) == '[object Array]'

const collect = pairs => pairs.reduce(
  (a, [k, v]) => ({...a, [k]: isArray(v) ? collect(v) : v}),
  {}
)

const spread = val => obj => Object.entries(obj)
  .filter(([k, v]) => v == val || isObject(v))
  .map(([k, v]) => isObject(v) ? [k, spread(val)(v)] : [k, v])

const findMatchingKeys = (val, obj) => collect(spread(val)(obj))

console.log(findMatchingKeys('Y', form))

此解决方案不使用 Ramda。我是 Ramda 的创始人之一,也是图书馆的忠实粉丝,但我认为 Ramda 在这里提供的帮助不多,只是进行了一些小的清理工作。

【讨论】:

  • 感谢您的解决方案。
【解决方案2】:

您的尝试已接近尾声,您只需为在对象值中找到的每个对象递归调用 map

const form = { A_ALL: {A1_ALL: { A1_ONE: 'Y', A2_TWO: 'Y', A3_THREE: 'Y'}, A2: {A2_FOUR: 'Y', A2_FIVE: 'N', A2_SIX: 'Y'}, A3: 'Y', A4: 'N'}, B_ALL: {B1_ALL: { B1_ONE: 'Y', B1_TWO: 'Y', B1_THREE: 'Y'}, B2: {B2_FOUR: 'Y', B2_FIVE: 'Y', B2_SIX: 'Y'}, B3: 'Y', B4: 'Y'}, C_ALL: {XX: 'Y', YY:'Y'}, D: 'Y', E: 'N' }

const eY = R.equals('Y') 
const isSelected = R.compose(R.all(eY), R.values) 
const groupValue = R.when(isSelected, R.always('Y'))

const fn = objOrString => R.pipe(
  R.unless(R.is(String), R.map(fn)),
  R.unless(R.is(String), groupValue),
  R.unless(R.is(String), R.filter(R.either(R.is(Object), R.equals('Y'))))
)(objOrString)

console.log(fn(form))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>

【讨论】:

  • 这是我所做的更简洁的版本。但两者都只是部分解决方案。如果您查看预期的输出,任何只有'Y' 值的子对象都应该变成'Y'
  • 我已经使用@smitach 已经拥有的函数(groupValue 和朋友)将仅包含“Y”的对象折叠为“Y”。但是,我确实错过了在所需输出中过滤掉所有“N”。我现在更新了答案,当子对象不仅由输入中的“Y”组成时,也可以从子对象中过滤掉非 Y 字符串。
  • 非常好!我正要回去解决这个问题。
  • 可以跳过objOrString参数和对应的(objOrString)吗?
  • Asad:如果我们要删除参数,fn 在评估 map(fn) 时仍然是未定义的。将其声明为函数会延迟对 map(fn) 的评估,直到定义 fn 之后。
【解决方案3】:

这是一种稍微不同的方法,(afaict)产生与斯科特克里斯托弗的回答相同的结果:

// Ramda doesn't support folding objects, so we have to define this here
// :: Monoid m -> (a -> m) -> StrMap a -> m
const foldMap = M => f => o =>
  R.keys(o).reduce((p, c) => M.append(p)(f(o[c])), M.empty);

// :: Monoid Boolean
const And = { empty: true, append: x => y => x && y };

// Each layer of the form can be thought of as a string map, where
// a key is mapped to one of the strings "Y" or "N", or to a value
// of some given type `a`
// :: type ValueOr a = "Y" | "N" | a
// :: type FormLayer a = StrMap (ValueOr a)

// We can think of a form as an infinite nesting of form layers
// :: type Fix f = f (Fix f)
// :: type Form = Fix FormLayer
//              = FormLayer (FormLayer (FormLayer (FormLayer ...)))

// Recursion schemes can help us promote a function for operating
// on one layer of the structure to a function that operates on an
// infinite nesting of layers
// :: Functor f -> (f a -> a) -> Fix f -> a
const cata = F => alg => {
  const rec = x => alg(F.map(rec)(x));
  return rec;
};

// It's useful to factor repeated case analysis into a pattern
const ValOr = {
  Y: "Y",
  N: "N",
  Other: x => x,
  match: ({ Y, N, Other }) => v => v === "Y" ? Y : v === "N" ? N : Other(v),
  map: f => ValOr.match({ Y, N, Other: f })
};
const { Y, N, Other } = ValOr;

// :: Functor FormLayer
const FormLayer = { map: f => R.map(ValOr.map(f)) };

// :: ValueOr _ -> Boolean
const isY = ValOr.match({ Y: true, N: false, Other: _ => false });
// :: FormLayer _ -> Boolean
const allYs = foldMap(And)(isY);
// :: Form -> ValueOr Form
const squashYs = cata(FormLayer)(o => allYs(o) ? Y : Other(o));

// :: ValueOr _ -> Boolean
const isntN = ValOr.match({ Y: true, N: false, Other: _ => true });
// :: Form -> Form
const filterNs = cata(FormLayer)(R.filter(isntN));

// :: Form -> ValueOr Form
const f = R.pipe(
  // Squash Y-only objects recursively
  squashYs,
  // If the top level result is still a form, filter out the "N"s recursively
  ValOr.match({ Y, N, Other: filterNs })
);

// :: Form
const form = {
  A_ALL: {
    A1_ALL: { A1_ONE: "Y", A2_TWO: "Y", A3_THREE: "Y" },
    A2: { A2_FOUR: "Y", A2_FIVE: "N", A2_SIX: "Y" },
    A3: "Y",
    A4: "N"
  },
  B_ALL: {
    B1_ALL: { B1_ONE: "Y", B1_TWO: "Y", B1_THREE: "Y" },
    B2: { B2_FOUR: "Y", B2_FIVE: "Y", B2_SIX: "Y" },
    B3: "Y",
    B4: "Y"
  },
  C_ALL: { XX: "Y", YY: "Y" },
  D: "Y",
  E: "N"
};

// :: ValueOr Form
const result = f(form);

console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>

【讨论】:

    猜你喜欢
    • 2012-12-26
    • 2015-06-19
    • 2018-02-02
    • 1970-01-01
    • 2023-03-21
    • 1970-01-01
    • 2016-04-23
    • 2015-10-19
    • 2016-10-09
    相关资源
    最近更新 更多