javascript - 在 JavaScript 中,reduce 之后按字段分组不起作用

标签 javascript ecmascript-6 ecmascript-5

有一个复杂的对象,并且基于作为输入给出的数组,我需要修改其属性。插图如下所示。如果“字段”相同,则将它们添加到“或”数组。如果“字段”不同,则将它们及其“值”添加到“和”数组。我使用 Set 从源和输入获取键,并使用它们根据其键进行分组。此外,每当存在重复项时,假设“filterObj”已经具有相同的(字段,值)对。无论是在“and”中还是在“or”中,那么就不要将其添加到最终对象中

沙盒: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);

最佳答案

尝试一下。 我重新实现了,它发生得更普遍。 根据它找到的算法解析任何过滤器。 所有测试用例均有效。

沙盒链接: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));

编辑 1

我没有改变逻辑;我基于它做了一个功能。

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

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

function appendToFilter(filter, inputObjects) {
  var storeMap = {};
  var counter = 0;
  var handlingQueue = [];
  // if filter isset the appen to handling queue
  if (filter.hasOwnProperty("filter")) {
    handlingQueue.push(filter.filter);
  }
  // append other object to queue
  handlingQueue.push(inputObjects);
  // get first and remove from queue
  var currentObject = handlingQueue.shift();
  while (currentObject !== undefined) {
    if (Array.isArray(currentObject)) {
      currentObject.forEach(element => handlingQueue.push(element));
    } else if (typeof currentObject === "object") {
      if (currentObject.hasOwnProperty("and") || currentObject.hasOwnProperty("or")) {
        for (var key in currentObject) {
          if (currentObject.hasOwnProperty(key)) {
            handlingQueue.push(currentObject[key]);
          }
        }
      } else {
        // TODO: append fild exists check
        if (currentObject.field) {
          if (!storeMap.hasOwnProperty(currentObject.field)) {
            storeMap[currentObject.field] = [];
          }
          var localValue = currentObject.value;
          // check duplicate
          if (storeMap[currentObject.field].find(object => object.value === localValue) === undefined) {
            counter++;
            storeMap[currentObject.field].push(currentObject);
          } 
        } 
      }
    }

    currentObject = handlingQueue.shift();
  }

  // create new filter settings

  var newFilter = {};

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

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

// update filterObj
appendToFilter(filterObj, obj);
console.log(filterObj);

编辑 2,3(已更新)

与其他对象的支持。

export function appendToFilter(filter, inputObjects) {
  var storeMap = {};
  var others = [];
  var counter = 0;
  var handlingQueue = [];
  // if filter isset the appen to handling queue
  if (filter.hasOwnProperty("filter") && filter.filter.hasOwnProperty("and")) {
    handlingQueue.push(filter.filter.and);
  }
  // append other object to queue
  handlingQueue.push(inputObjects);
  // get first and remove from queue
  var currentObject = handlingQueue.shift();
  while (currentObject !== undefined) {
    if (Array.isArray(currentObject)) {
      currentObject.forEach(element => handlingQueue.push(element));
    } else if (typeof currentObject === "object") {
      if (
        currentObject.hasOwnProperty("and") ||
        currentObject.hasOwnProperty("or")
      ) {
        for (var key in currentObject) {
          if (currentObject.hasOwnProperty(key)) {
            handlingQueue.push(currentObject[key]);
          }
        }
      } else {
        // TODO: append fild exists check
        if (currentObject.field) {
          if (!storeMap.hasOwnProperty(currentObject.field)) {
            storeMap[currentObject.field] = [];
          }
          var localValue = currentObject.value;
          // check duplicate
          if (
            storeMap[currentObject.field].find(
              object => object.value === localValue
            ) === undefined
          ) {
            counter++;
            storeMap[currentObject.field].push(currentObject);
          }
        } else {
          // handle others objects^ without field "field"
          counter++;
          others.push(currentObject);
        }
      }
    }
    currentObject = handlingQueue.shift();
  }
  // create new filter settings
  var newFilter = {};
  // check exists root filter and filed if have objects
  if (counter > 0) {
    newFilter["and"] = [];
  }
  for (var storeKey in storeMap) {
    if (storeMap.hasOwnProperty(storeKey)) {
      var array = storeMap[storeKey];
      if (array.length > 1) {
        newFilter["and"].push({
          // clone array
          or: array.slice()
        });
      } else {
        newFilter["and"].push(array[0]);
      }
    }
  }
  // Append others to result filter
  others.forEach(other => newFilter["and"].push(other));
  filter.filter = newFilter;
}

关于javascript - 在 JavaScript 中,reduce 之后按字段分组不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59859914/

相关文章:

typescript - 如何避免在 Angular 2 中导入相对路径很长的内容?

javascript - 为什么这个递归函数会覆盖第二次调用的值?

javascript - 澄清 Typescript 的目标和库设置的功能

javascript - ECMAScript 5 在任何浏览器中可用吗?

javascript - 使用 React 引用嵌套 Javascript 数组的列值

javascript - 加速 Nivo-Slider

javascript - (为什么)我不能从生成器中抛出异常吗?

javascript - 在 JavaScript 中,为什么除了字符串之外,任何对象都不相等?

javascript - 从 html 表中选择多行并将值发送到 javascript 中的函数

c# - 使用c#命令保存js文件