Javascript reduce() для объекта

#javascript #json #object #reduce

Вопрос:

У меня есть объект javascript ниже:

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

И я получил два ввода: 'numbers' и ['4','5']

Я хочу получить:

 {
            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,
            }
}
 

И когда я ввожу два других ввода: 'words' и ['please']

Я хочу получить:

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

Как это сделать с помощью reduce() ?

Комментарии:

1. в общем, я думаю, что вы могли бы преобразовать объект в массив, а затем уменьшить

Ответ №1:

Вам нужно получить записи объекта перед использованием 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])) 

Ответ №2:

Для меня проще всего объединить входные данные в объект с одинаковыми номерами и ключами слов.

Затем повторите Object.entries() и сопоставьте ключи чисел/слов между объектами ввода и фильтра

 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) 

Ответ №3:

Держи. Не так, как я бы это сделал, но если вам нужно использовать 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',
  },
}

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;
    }, {})
  }
} 

Ответ №4:

Использование двух reduce() для фильтрации внутреннего объекта и внешнего объекта.

 /* 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)
  };
}
 

Назовите его с данными, которые вы дали в первом аргументе, как:

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

Вот полный код, который вы можете протестировать и запустить.

 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'])); 

Ответ №5:

Конечно, очень простой код в одну строку

 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'])) 

Ответ №6:

Базовое решение:

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

преобразуйте его в уменьшенную версию карты:

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

Ответ №7:

таким образом…

 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 } 

Ответ №8:

Вы можете уменьшить свои numbers и words объекты, уменьшив их Object.entries (), который возвращает одну array из пар собственных перечисляемых свойств объекта [key, value] .

 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'])); 

Обратите внимание, что оба выражения функции редуктора используют приведенные выше задания разрушения, чтобы легко разбить [key, value] пары.

Комментарии:

1. почему свойство жестко закодированного фильтра и две идентичные функции?

2. @Bravo Спасибо вам за конструктивную критику. Я прошу вас еще раз просмотреть мой ответ.

3. теперь это выглядит так же, как половина всех остальных ответов — так что, да, это замечательно

Ответ №9:

Я бы сделал что-то вроде ниже

 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']));