reduce后按字段分组在JavaScript中不起作用

问题描述 投票:0回答:1

存在一个复杂的对象,并且基于作为输入提供的数组,我需要修改其属性。插图如下所示。如果“字段”相同,则将它们添加到“或”数组中。如果其不同的“字段”,则将它们及其“值”添加到“和”数组中。我正在使用Set从源和输入中获取键,并使用它们基于其键进行分组。同样,只要有重复,即,假设“ filterObj”已经具有相同的(字段,值)对。无论是在“和”中还是在“或”中,都不要将其添加到最终对象中

沙盒:https://codesandbox.io/s/optimistic-mirzakhani-pogpw-so-dpvis

沙箱中有一个需要通过的TestCases文件

let filterObj = {
  feature: "test",
  filter: {
    and: [{ field: "field2" }]
  }
};
let obj = [{ field: "field2", value: "3" }];
let all_filters = [];
if (filterObj.filter.and && filterObj.filter.and.hasOwnProperty("or")) {
  all_filters = [...filterObj.filter.and.or];
} else if (filterObj.filter.and) {
  all_filters = [...filterObj.filter.and];
}
const all_objs = [...obj, ...all_filters];
const uniqKeys = all_objs.reduce(
  (acc, curr) => [...new Set([...acc, curr.field])],
  []
);
const updateItems = uniqKeys.map(obj => {
  const filter_items = all_objs.filter(item => item.field === obj);
  let resultObj = {};
  if (filter_items && filter_items.length > 1) {
    resultObj.or = [...filter_items];
  } else if (filter_items && filter_items.length === 1) {
    resultObj = { ...filter_items[0] };
  }
  return resultObj;
});
var result = { ...filterObj, filter: { and: [...updateItems] } };
console.log(result);

javascript ecmascript-6 ecmascript-5
1个回答
0
投票

尝试一下。我重新实施,它发生得更普遍。根据找到的算法解析所有过滤器。所有测试用例均正常工作。

沙盒链接:https://codesandbox.io/s/optimistic-mirzakhani-pogpw-so-i1u6h

let filterObj = {
  feature: "test",
  filter: {
    and: [
      {
        field: "field1",
        value: "2"
      }
    ]
  }
};

let obj = [
  {
    field: "field1",
    value: "2"
  },
  {
    field: "field1",
    value: "1"
  }
];

var FilterController = function(filter) {
  var self = this;
  self.filter = filter;
  // encapsulated map of objects by fields
  var storeMap = {};
  // counter of objects
  var counter = 0;

  var tryPutObjectToMap = function(object) {
    if (typeof object === "object") {
      // get type for grouping
      var objectType = self.getObjectGroupType(object);
      if (objectType !== null) {
        // cheack have group
        if (!storeMap.hasOwnProperty(objectType)) {
          storeMap[objectType] = [];
        }

        var duplicate = storeMap[objectType].find(function(sObject) {
          return self.getObjectValue(sObject) === self.getObjectValue(object);
        });

        // check duplicate
        if (duplicate === undefined) {
          counter++;
          storeMap[objectType].push(object);
        } else {
          // TODO: Handle duplicates
        }
      } else {
        // TODO: handle incorrect object
      }
    }
  };

  // get filter structure from map
  var getFilterStructureFromMap = function() {
    var result = {};

    // check exists root filter and filed if have objects
    if (counter > 0) {
      result["and"] = [];
    }

    for (var key in storeMap) {
      if (storeMap.hasOwnProperty(key)) {
        var array = storeMap[key];
        if (array.length > 1) {
          result["and"].push({
            // clone array
            or: array.slice()
          });
        } else {
          result["and"].push(array[0]);
        }
      }
    }
    return result;
  };

  // rewrite and get current filter
  // if you need^ create new object for result
  self.rewriteAndGetFilter = function() {
    self.filter.filter = getFilterStructureFromMap();
    return self.filter;
  };

  // not prototype function for have access to storeMap
  self.putObjects = function(objects) {
    if (Array.isArray(objects)) {
      // recursive push array elements
      objects.forEach(element => self.putObjects(element));
      // handle array
    } else if (typeof objects === "object") {
      // handle object
      if (objects.hasOwnProperty("and") || objects.hasOwnProperty("or")) {
        for (var key in objects) {
          //no matter `or` or `and` the same grouping by field
          // inner object field
          if (objects.hasOwnProperty(key)) {
            self.putObjects(objects[key]);
          }
        }
      } else {
        // filters props not found, try push to store map
        tryPutObjectToMap(objects);
      }
    } else {
      // TODO: Handle errors
    }
  };

  if (self.filter.hasOwnProperty("filter")) {
    // put and parse current objects from filter
    self.putObjects(self.filter.filter);
  }
};

// function for grouping objects.
// for you get filed name from object.
// change if need other ways to compare objects.
FilterController.prototype.getObjectGroupType = function(obj) {
  if (typeof obj === "object" && obj.hasOwnProperty("field")) {
    return obj.field;
  }
  return null;
};

// get object value
FilterController.prototype.getObjectValue = function(obj) {
  if (typeof obj === "object" && obj.hasOwnProperty("value")) {
    return obj.value;
  }
  return null;
};

var ctrl = new FilterController(filterObj);
ctrl.putObjects(obj);
var totalFilter = ctrl.rewriteAndGetFilter();
console.log(totalFilter);
console.log(JSON.stringify(totalFilter));

© www.soinside.com 2019 - 2024. All rights reserved.