如何使用Ramda JS对对象进行排序

时间:2019-01-11 00:35:49

标签: javascript sorting filtering ramda.js

我要对以下对象进行排序

    class A{
    public:
        int x;

        int getA(){return x;}
        int getB(){return this->x;}
        void setA(int val){ x = val;}
        void setB(int val){ this->x = val;}

    };

    int main(int argc, const char * argv[]) {
        A objectA;
        A objectB;

        object.setA(33);
        std::cout<< object.getA() << "\n";

        objectB.setB(32);
        std::cout<< object.getB() << "\n";

        return 0;
    }

我正在实现带有嵌套复选框的表单,其值可以是“ Y”或“ N”。我只想捕获“ 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'
}

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

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

3 个答案:

答案 0 :(得分:1)

您已尝试关闭,只需要递归调用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>

答案 1 :(得分:0)

我有一个局部解决方案,目前没有时间进行下一步。本质上,它过滤掉不是'Y'的所有值。然后,您应该能够通过递归地替换仅包含'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 :(得分:0)

这里的方法略有不同,(确实)产生的结果与Scott Christopher的答案相同:

// 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>