1

I have a javascript object below:

let filters = {
 numbers: {
 '0': 'is_no_selected',
 '1': 'is_one_selected',
 '2': 'is_two_selected',
 '3': 'is_three_selected',
 '4': 'is_four_selected',
 '5': 'is_five_selected',
 },
 words: {
 please: 'is_please_selected',
 help: 'is_help_selected',
 me: 'is_me_selected',
 },
}

And I got two input:'numbers' and ['4','5']

I want to get:

{
 numbers: {
 'is_no_selected': false,
 'is_one_selected': false,
 'is_two_selected': false,
 'is_three_selected': false,
 'is_four_selected': true,
 'is_five_selected': true,
 }
}

And when I input other two input:'words' and ['please']

I want to get:

{
 words: {
 'is_please_selected': true,
 'is_help_selected': false,
 'is_me_selected': false,
 }
}

How to make this happen using reduce()?

asked Aug 13, 2021 at 2:14
1
  • in general, I guess you could convert object to Array then reduce Commented Aug 13, 2021 at 2:28

9 Answers 9

1

You need to get the entries of the object before using reduce:

let filters = {
 numbers: {
 '0': 'is_no_selected',
 '1': 'is_one_selected',
 '2': 'is_two_selected',
 '3': 'is_three_selected',
 '4': 'is_four_selected',
 '5': 'is_five_selected',
 },
 words: {
 please: 'is_please_selected',
 help: 'is_help_selected',
 me: 'is_me_selected',
 },
}
function fn(obj, filterKey, filters) {
 filters = filters.map(x => ''+x); // convert all filters to strings (keys are always string)
 return Object
 .keys(obj)
 .filter(x => x === filterKey) // only the selected property
 .map(x => obj[x]) // get the object
 .map(x => {
 return Object.entries(x).reduce((out, curr) => {
 const [key, val] = curr;
 out[val] = filters.includes(key);
 return out;
 }, {})
 });
}
console.log(fn(filters, 'numbers', [0]))

answered Aug 13, 2021 at 2:42
Sign up to request clarification or add additional context in comments.

Comments

1

I'd do something like below

const process = function (data, key, input) {
 const result = Object.keys(data[key])
 .reduce((acc, index) => {
 const isValid = input.includes(index);
 if(isValid)
 acc[data[key][index]] = true;
 else 
 acc[data[key][index]] = false;
 return acc;
 }, {});
 return {
 [key] : result
 }
};
var filters = {
 numbers: {
 '0': 'is_no_selected',
 '1': 'is_one_selected',
 '2': 'is_two_selected',
 '3': 'is_three_selected',
 '4': 'is_four_selected',
 '5': 'is_five_selected',
 },
 words: {
 please: 'is_please_selected',
 help: 'is_help_selected',
 me: 'is_me_selected',
 },
};
// client code: process(filters, 'numbers', ['4', '5']));
answered Aug 13, 2021 at 2:43

Comments

1

For me the simplest is to combine the inputs into an object with the same numbers and words keys.

Then iterate the Object.entries() and match the numbers/words keys between input and filter objects

let filters={numbers:{0:"is_no_selected",1:"is_one_selected",2:"is_two_selected",3:"is_three_selected",4:"is_four_selected",5:"is_five_selected"},words:{please:"is_please_selected",help:"is_help_selected",me:"is_me_selected"}};
const inputs = {
 numbers: ['4', '5'],
 words: ['please'],
};
const res = {};
Object.entries(filters).forEach(([key,o])=>{
 const fil = res[key] = {}; 
 Object.entries(o).forEach(([k,v]) => fil[v] = inputs[key].includes(k));
})
console.log(res)

answered Aug 13, 2021 at 2:44

Comments

1

Here you go. Not how I would have done it, but if you must use reduce, you can do it like this.

let filters = {
 numbers: {
 '0': 'is_no_selected',
 '1': 'is_one_selected',
 '2': 'is_two_selected',
 '3': 'is_three_selected',
 '4': 'is_four_selected',
 '5': 'is_five_selected',
 },
 words: {
 please: 'is_please_selected',
 help: 'is_help_selected',
 me: 'is_me_selected',
 },
}
var numbers = filter(filters, 'numbers', ['4', '5']);
var words = filter(filters, 'words', ['please']);
console.log(numbers);
console.log(words);
function filter(filter_obj, key, input) {
 return {
 [key]: Object.keys(filters[key]).reduce((a, c) => {
 a[filters[key][c]] = input.includes(c)
 return a;
 }, {})
 }
}

answered Aug 13, 2021 at 2:30

Comments

1

Using two reduce() for filtering the inner object and the outer object.

/* input is the data and filtering key and value list */
function filter (data, key, vals) {
 // inner filter
 const filterValues = (obj, values) => Object.keys(obj).reduce((accum, ele) => {
 accum[obj[ele]] = values.includes(ele);
 return accum;
 }, {});
 // outer filter
 const filteredKey = Object.keys(data).reduce((accum, ele) => {
 if (ele === key)
 accum[key] = data[key];
 return accum;
 }, {});
 // call outer filter first then pass it to inner filter
 return {
 [key]: filterValues(filteredKey[key], vals)
 };
}

Call it with the data you gave in the firs argument as:

console.log(filter(data, 'numbers', ['4', '5']));
console.log(filter(data, 'words', ['please']));

Here is the complete code you can test and run.

const data = {
 numbers: {
 '0': 'is_no_selected',
 '1': 'is_one_selected',
 '2': 'is_two_selected',
 '3': 'is_three_selected',
 '4': 'is_four_selected',
 '5': 'is_five_selected',
 },
 words: {
 please: 'is_please_selected',
 help: 'is_help_selected',
 me: 'is_me_selected',
 },
}
/* input is data and filtering key and value list */
function filter (data, key, vals) {
 // inner filter
 const filterValues = (obj, values) => Object.keys(obj).reduce((accum, ele) => {
 accum[obj[ele]] = values.includes(ele);
 return accum;
 }, {});
 // outer filter
 const filteredKey = Object.keys(data).reduce((accum, ele) => {
 if (ele === key)
 accum[key] = data[key];
 return accum;
 }, {});
 // call outer filter first then pass it to inner filter
 return {
 [key]: filterValues(filteredKey[key], vals)
 };
}
console.log(filter(data, 'numbers', ['4', '5']));
console.log(filter(data, 'words', ['please']));

answered Aug 13, 2021 at 2:56

Comments

1

Sure, very simple one line code

let filters = {
 numbers: {
 '0': 'is_no_selected',
 '1': 'is_one_selected',
 '2': 'is_two_selected',
 '3': 'is_three_selected',
 '4': 'is_four_selected',
 '5': 'is_five_selected',
 },
 words: {
 please: 'is_please_selected',
 help: 'is_help_selected',
 me: 'is_me_selected',
 },
}
const fn=(f,a)=>({[f]:Object.entries(filters[f]).reduce((r,[k,v])=>(r[v]=a.includes(k),r),{})});
console.log(fn('numbers', ['4','5']))
console.log(fn('words',['please']))

answered Aug 13, 2021 at 2:59

Comments

1

A Basic solution:

function filter(all_option, select_key, select_option) {
 let ret = {};
 let s_f = all_option[select_key];
 for (let k in s_f) {
 if (select_option.includes(k)) {
 ret[s_f[k]] = true;
 } else {
 ret[s_f[k]] = false;
 }
 }
 return ret;
}

convert it to map reduce version:

function filter(all_option, select_key, select_option) {
 let ret = {};
 let s_f = all_option[select_key];
 Object.keys(s_f).map(k => {
 if (select_option.includes(k)) {
 ret[s_f[k]] = true;
 } else {
 ret[s_f[k]] = false;
 }
 });
 return ret;
}
answered Aug 13, 2021 at 2:43

Comments

1

this way...

const filters = 
 { numbers: 
 { '0': 'is_no_selected'
 , '1': 'is_one_selected'
 , '2': 'is_two_selected'
 , '3': 'is_three_selected'
 , '4': 'is_four_selected'
 , '5': 'is_five_selected'
 } 
 , words: 
 { please: 'is_please_selected'
 , help: 'is_help_selected'
 , me: 'is_me_selected'
 } 
 } 
const foo = (in1,in2) =>
 Object.entries(filters[ in1 ])
 .reduce((r,[k,v]) => Object.assign(r,{[v]:in2.includes(k)}), {})
console.log('a;', foo('numbers', ['4','5']) )
console.log('b;', foo('words', ['please']) )
.as-console-wrapper { max-height: 100% !important; top: 0 }

answered Aug 13, 2021 at 2:58

Comments

1

You can reduce your numbers and words objects by reducing their Object.entries() which returns an array of an object's own enumerable property [key, value] pairs.

let filters = {
 numbers: {
 '0': 'is_no_selected',
 '1': 'is_one_selected',
 '2': 'is_two_selected',
 '3': 'is_three_selected',
 '4': 'is_four_selected',
 '5': 'is_five_selected',
 },
 words: {
 please: 'is_please_selected',
 help: 'is_help_selected',
 me: 'is_me_selected',
 },
};
let reduceFilter = function(filters, name, input) {
 return Object.entries(filters[name]).reduce((acc, [key, value]) => {
 acc[name][value] = input.includes(key);
 return acc;
 }, {[name]: {}}); 
};
console.log(reduceFilter(filters, 'numbers', ['4', '5']));
console.log(reduceFilter(filters, 'words', ['please']));

Notice that both the reducer function expressions make use of destructing assignments above to break apart the [key, value] pairs easily.

answered Aug 13, 2021 at 2:44

3 Comments

why the hard coded filter property and two identical functions?
@Bravo Thank you for your constructive critique. I request you to review my answer again.
now it looks just like half of all the other answers - so, yeah, that's wonderful

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.