编辑JSON对象-寻找更好的功能方法

Edit JSON object - looking for better functional approch

本文关键字:功能 方法 更好 寻找 JSON 对象 编辑      更新时间:2023-09-26

我有一个JSON对象设置,类似于这样:

var settings = {
  tab1: {
    active: true,
    selectOrder: 1,
    selected: false
  },
  tab2: {
    active: true,
    selectOrder: 2,
    selected: false
  },
  tab3: {
    active: false,
    selectOrder: 0,
    selected: false
  }
};

现在,我的目标是为具有最低'selectedOrder'的活动元素设置'selected'属性为'true'。在这个例子中,我应该为'tab1'元素设置'selected' ('tab3'的selectedOrder为0,但不是活动的)。

其背后的原因是选择第一个活动选项卡根据其优先级(selectOrder)。

我的解决方案是:

function selectFirstActiveTab(visibilitySettings) {
  var selected = 1000;
  var answer = jQuery.extend({}, visibilitySettings);
  Object.keys(answer).forEach((key) => {
    if (answer[key].active && answer[key].selectOrder <= selected) {
      selected = answer[key].selectOrder;
    }
  });
  Object.keys(answer).forEach((key) => {
    answer[key].selected = (answer[key].selectOrder === selected) ? true : false;
  });
  return answer;
};

虽然这个解决方案是有效的,但它似乎是一个糟糕的解决方案。

我的问题是:

  1. 是否有更好的"函数式编程"方法?(例如使用map/reduce等)

  2. 我感觉我的设置对象结构不太好。也许我应该选择对象数组而不是JSON?选择像这样的JSON的原因是为了更简单地绑定到我的模板(像"{{settings .tab1。Selected}}" -比在我的html中查找更简单)。这里应该有什么更好的方法?

下面是JSBIN
中的完整示例
  1. 对于Object上的map和reduce,您可以使用下划线:
function selectFirstActiveTab(visibilitySettings) {
  // Clone input, with selected set to false.
  var answer = _.mapObject(visibilitySettings, (item, key) => {
    return {active: item.active, selectOrder: item.selectOrder, selected: false};
  });
  // Find the min among all value.
  var minObj = _.reduce(answer, (min, item) => {
    return (item.active && item.selectOrder < min.selectOrder) ? item : min;
  }, {active: true, selectOrder: Number.MAX_SAFE_INTEGER});
  // Set min to selected.
  minObj.selected = true;
  return answer;
};

jsBin

或香草javascript:

function selectFirstActiveTab(visibilitySettings) {
  var keys = Object.keys(visibilitySettings);
  // Create a cloned obj, like map
  var answer = {};
  keys.forEach((key) => {
    var cloneTarget = visibilitySettings[key];
    answer[key] = {
      active: cloneTarget.active,
      selectOrder: cloneTarget.selectOrder,
      selected: false
    };
  });
  // Convert key => value map to an array of value, then reduce it to find min.
  var minimun = keys.map((key) => answer[key]).reduce((min, item) => {
    return (item.active && item.selectOrder < min.selectOrder) ? item : min;
  }, {active: true, selectOrder: Number.MAX_SAFE_INTEGER});
  // Set min to selected.
  minimun.selected = true;
  return answer;
};

jsBin

  • 它不是JSON,它只是一个普通的Object与一些键值映射,我们使用它作为Map。如果输入是一个像
  • 这样的数组,那么应用上面的逻辑可能会更容易:

    var settings = [
      {
        name: 'tab1',
        active: true,
        selectOrder: 1,
        selected: false
      },
      {
        name: 'tab2',
        active: true,
        selectOrder: 2,
        selected: false
      },
      {
        name: 'tab3',
        active: false,
        selectOrder: 0,
        selected: false
      }
    ];
    

    作为香草javascript支持减少/映射在array。然而,像lodash、underscore这样的许多库只是使reduce/map在对象上可用。你可以只需选择最适合您需求的一个(因为有许多类似的库,使您能够通过对象映射/减少)。

    使用lodash,您可以编写以下内容:

    import { chain, transform, extend } from 'lodash';
    transformObj = (obj) => chain(settings)
      .map((obj, key)=> ({ key, obj }))
      .select(({ obj: { active }})=> active)
      .min(({ obj: { selectOrder }})=> selectOrder)
      .thru(({ key })=> transform(settings, (memo, val, _key) => {
          memo[_key] = extend({}, val, {
            selected: (_key == key)
          })
        }, {})
      )
      .value()
    

    > transformObj(settings)
    { tab1: { active: true, selectOrder: 1, selected: true },
      tab2: { active: true, selectOrder: 2, selected: false },
      tab3: { active: false, selectOrder: 0, selected: false } }
    

    以上假设了ES6导入、箭头函数和参数解构的可用性。否则可以使用babel。

    这个功能更强大,因为transformObj是引用透明的&不会改变它的参数。

    Try this:

    tmp = 0;
    _tab = false;
    for ( tab in settings ){
        if((settings[tab].active)){
            if(!tmp){
                tmp = settings[tab].selectOrder;
                _tab  = tab;
            }else if(settings[tab].selectOrder < tmp){
                _tab = tab;
            }
        };
    }
    settings[_tab].selected = true;