简体   繁体   中英

How to sort object with ramda js

I want to sort the following object,

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'
}

I am implementing a form with nested check boxes who's value can be 'Y' or 'N'. I want to capture only the 'Y' check boxes, and if all of the child check boxes are 'Y', I want to discard them and get only parent checkbox. Above is the object which has all the check box values. I want the object to be sorted to:

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

My code so far looks like this:

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"}}

You're close with your attempt, you just need to recursively call map for each object that it finds in the values of the object.

 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> 

I have a partial solution, and no time at the moment to take the next step. It essentially filters out any values that are not 'Y' s. You should then be able to add another step to slim this down by recursively replacing values which are objects containing only 'Y' values with just '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)) 

This solution doesn't use Ramda. I'm one of the founders of Ramda, and a big fan of the library, but I don't see Ramda offering much help here, only a few minor clean-ups.

Here is a slightly different approach that (afaict) produces the same result as Scott Christopher's answer:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM