【问题标题】:How to dynamically build array filter expression in javascript如何在javascript中动态构建数组过滤器表达式
【发布时间】:2020-07-23 15:02:36
【问题描述】:

我需要一个函数来过滤我的数组并根据用户输入返回结果。

var Myarray= [
  {Date:"1-Jan-2020",Name:"A", Id: 1},
  {Date:"1-Feb-2020",Name:"B", Id: 2},
  {Date:"1-Mar-2020",Name:"C", Id: 3}
  ...
]

过滤器需要是动态的。用户必须至少输入日期或姓名或同时输入两者。 ID 是可选的

有没有一种聪明的方法可以根据用户输入的内容在函数中构建过滤器表达式?

更多信息: 我有一个用户界面。用户将有搜索参数可供选择返回日期。日期、姓名和 ID。用户必须至少选择日期或名称。 ID 是可选的,但必须在接受发送参数的函数中考虑。用户输入值后,它们被传递给一个 JS 函数,该函数应该过滤一个保存数据的数组。将过滤器应用于数组后,将使用过滤后的数据填充一个新数组。 Ex.user 发送没有名称或 ID 的日期,然后数组仅根据日期进行过滤。例 2。用户发送不带日期或 ID 的名称,然后数组仅根据名称过滤。例 3。用户发送不带 id 的日期和名称,然后根据日期和名称进行数组过滤。例 4。用户发送不带名称的日期和 ID,然后根据日期和 ID 进行数组过滤。例 5。用户发送不带日期的名称和 ID,然后按名称和 ID 进行数组过滤。 ex6 用户发送日期、姓名和 ID,然后根据日期、姓名和 ID 进行数组过滤。 Ex7 用户发送 id,功能不允许单独发送 id 没有日期或名称

【问题讨论】:

  • 分享您的研究对每个人都有帮助。告诉我们您尝试了什么以及为什么它不能满足您的需求。这表明您已经花时间尝试帮助自己,它使我们免于重复明显的答案,最重要的是它可以帮助您获得更具体和相关的答案!另见How to Ask

标签: javascript function dynamic


【解决方案1】:

您可以使用Array.prototype.some (OR) 来链接谓词。如果在任何时候一个谓词匹配,整个项目将被添加到结果列表中。

如果您希望所有条件都匹配,则需要使用Array.prototype.every (AND) 链接。

我可能很快就会回到这个,举一个更动态的例子。 见下文。

const main = () => {
  let arr = [
    { Date: "1-Jan-2020" , Name: "A"  , Id: 1 }, // Yes
    { Date: "1-Feb-2020" , Name: "B"  , Id: 2 }, // Yes
    { Date: "1-Mar-2020" , Name: null , Id: 3 }, // Yes
    { Date: null         , Name: null , Id: 4 }  // No
  ]
  
  console.log(filterWithPredicates(arr, predicates))
}

const predicates = {
  date: (record) => record.Date != null,
  name: (record) => record.Name != null
};

const filterWithPredicates = (list, predicates) => {
  return list.filter(item => {
    return Object.values(predicates).some(predicate => {
      if (predicate(item)) { return true }
    })
    return false
  })
}

main()
.as-console-wrapper { top: 0; max-height: 100% !important; }

这是一个谓词链接的例子。

const Predicates = {
  date: (record) => record.Date != null,
  name: (record) => record.Name != null
}

const main = () => {
  let arr = [
    { Date: "1-Jan-2020" , Name: "A"  , Id: 1 }, // Yes
    { Date: "1-Feb-2020" , Name: "B"  , Id: 2 }, // Yes
    { Date: "1-Mar-2020" , Name: null , Id: 3 }, // Yes
    { Date: null         , Name: null , Id: 4 }  // No
  ]
  
  let filter = new Filter().chain().or(Predicates.date).or(Predicates.name)
  console.log(filter.execute(arr))
}

class Filter {
  constructor() {
    this.filters = []
  }
  chain() {
    this.filters = []
    return this
  }
  or(predicate) {
    this.filters.push({ fn : predicate, op : 'or' })
    return this
  }
  and(predicate) {
    this.filters.push({ fn : predicate, op : 'and' })
    return this
  }
  execute(items) {
    return items.reduce((results, item) => 
      this.__shouldKeepItem(item) ? results.concat(item) : results, [])
  }
  /** @private */
  __startCondition() {
    return this.filters.length ? this.filters[0].op === 'and' ? 1 : 0 : 0
  }
  /** @private */
  __shouldKeepItem(item) {
    return this.filters.reduce((keep, filter) => {
      switch (filter.op) {
        case 'or'  : return keep || filter.fn(item)
        case 'and' : return keep && filter.fn(item)
        default    : return keep
      }
    }, this.__startCondition())
  }
}

main()
.as-console-wrapper { top: 0; max-height: 100% !important; }

【讨论】:

  • 您的解决方案似乎不错,但是我对 JS 很陌生,不太了解。我也看不到您如何处理可选的 Id 参数?我会等待你更动态的例子
  • @MutasemSallam 如果 ID 是可选的,那么您根本不对其进行过滤。
  • 您能否在代码中内联 cmets 以了解每行的工作方式?我无法理解。是的,id 是可选的,但用户仍然可以根据需要选择它。所以必须考虑它的参数是否为空
  • 我在我的问题中添加了更多信息。请检查一下
【解决方案2】:

const Myarray= [
  {Date:"1-Jan-2020",Name:"A", Id: 1},
  {Date:"1-Feb-2020",Name:"B", Id: 2},
  {Date:"1-Mar-2020",Name:"C", Id: 3}
];

const customFilter = (array, expr) => {
  if (Object.keys(expr).length == 0) {
    console.log("Error! missing at least one filter expression");
    return null;
  }
  /* if expression doesn't exist it's a pass for all items */
  return array.filter(item => !expr.Date || item.Date == expr.Date).filter(item => !expr.Name || item.Name == expr.Name).filter(item => !expr.Id || item.Id == expr.Id)
}

console.log(customFilter(Myarray, {Date: "1-Jan-2020", Name: "B"}))
console.log(customFilter(Myarray, {Date: "1-Jan-2020"}))
console.log(customFilter(Myarray, {Name: "B"}))
console.log(customFilter(Myarray, {Id: 3}))
console.log(customFilter(Myarray, {}))

【讨论】:

  • 我不需要验证消息日志。过滤器表达式应该根据我在摘要中提供的条件为用户输入的任何内容动态构建。此外,Id 是可选的,但如果用户希望使用它,则必须在函数中处理它。
  • 您在发布问题时需要更加具体。提供一些示例输入/输出对。有许多不同的方式可以解释您在编码方面的要求。
  • 我有一个用户界面。用户将有搜索参数来选择返回数据。日期、名称和 ID。用户必须至少选择日期或名称。ID 是可选的,但必须在接受发送的参数的函数中考虑。用户输入值后,它们被发送到 JS过滤保存数据的数组的函数。将过滤器应用于数组后,新数组将填充过滤后的数据。 Ex.user 发送不带名称或 ID 的日期,然后数组只过滤日期。Ex2.user 发送不带日期或 id 的名称,然后数组只过滤名称。Ex3 用户发送 id,函数将不允许单独发送不带日期或的 id名称
【解决方案3】:

试试:

var filteredArray = Myarray.filter(function (item) {
   return item.Date !== undefined && item.Name !== undefined;
});
var filteredArrayWithOptionalId = Myarray.filter(function (item) {
   return item.Date !== undefined && item.Name !== undefined && item.Id !== undefined;
});

您现在有 2 个数组,一个包含必需的参数对象,另一个可以处理可选 ID。然后,您可以循环通过filteredArrayWithOptionalId来处理与ID相关的代码。

在此处查看类似问题的答案:How to filter object array based on attributes?

我还建议您将变量名小写,因为这是最佳实践,只要它们不是类即可。

【讨论】:

  • 我在我的问题中添加了更多信息。请检查一下
  • 好的,这个解决方案有没有更好的帮助?我做了两个数组,一个有可选属性,一个没有。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-17
  • 1970-01-01
  • 2016-11-25
  • 1970-01-01
相关资源
最近更新 更多