- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我正在构建一个声明式的基于类型的过滤器模型。我无法将事件过滤器的状态存储在属性中,因为我的协议(protocol)具有关联类型。``
我听说过Type Erasure,但我找到的所有示例都使用 super 简单的示例,但不知何故我无法将其映射到我的用例。
这是我的协议(protocol):
protocol Filter {
// The Type to be filtered (`MyModel`)
associatedtype ParentType
// The type of the property to be filtered (e.g `Date`)
associatedtype InputType
// The type of the possible FilterOption (e.g. `DateFilterOption` or the same as the Input type for filtering in enums.)
associatedtype OptionType
// This should return a list of all possible filter options
static var allOptions: [OptionType] { get }
static var allowsMultipleSelection: Bool { get }
// the adopting object will be setting this.
var selectedOptions: [OptionType] { get set }
func isIncluded(_ item: InputType) -> Bool
// For getting reference to the specific property. I think Swift 4's keypaths could be working here too.
var filter: FilterClosure<ParentType> { get }
}
以及具有减少复制/粘贴代码扩展的子协议(protocol)
protocol EquatableFilter: Filter where InputType: Equatable, OptionType == InputType {}
extension EquatableFilter {
var allowsMultipleSelection: Bool { return true }
func isIncluded(_ item: InputType) -> Bool {
if selectedOptions.count == 0 { return true }
return selectedOptions.contains(item)
}
}
// Another specific filter. See gist file for extension.
protocol DateFilter: Filter where InputType == Date, OptionType == DateFilterOption {}
更多代码,please see my gist通过示例模型查看我的实现方式。
如何存储包含 struct
实例的数组,符合不同的 Filter
协议(protocol)?
我如何存储一个只包含结构类型的静态数组,以便我可以访问静态属性?
最佳答案
有趣的是,我今年早些时候为一个商业项目构建了一些与此不同的东西。笼统地去做是有挑战性的,但是大部分问题都来自于逆向思考。 “以终为始。”
// I want to be able to filter a sequence like this:
let newArray = myArray.filteredBy([
MyModel.Filters.DueDateFilter(selectedOptions: [.in24hours(past: false)]),
MyModel.Filters.StatusFilter(selectedOptions: [.a, .b])
])
这部分非常简单。它甚至不需要 filteredBy
.只需添加 .filter
每个元素:
let newArray = myArray
.filter(MyModel.Filters.DueDateFilter(selectedOptions: [.in24hours(past: false)]).filter)
.filter(MyModel.Filters.StatusFilter(selectedOptions: [.a, .b]).filter)
如果你愿意,你可以通过这种方式编写过滤,并做同样的事情:
func filteredBy(_ filters: [(Element) -> Bool]) -> [Element] {...}
重点是Filter
这里并不是真正的“过滤器”。它是对过滤器的描述,还有很多关于 UI 的其他内容(我们稍后会详细讨论)。要实际过滤,您只需要 (Element) -> Bool
.
我们真正想要的是一种构建 ([Element]) -> Element
的方法用一个漂亮的,富有表现力的语法。在函数式语言中,这会非常简单,因为我们有部分应用程序和函数组合之类的东西。但是 Swift 并不真的喜欢做这些事情,所以为了让它更漂亮,让我们构建一些结构。
struct Filter<Element> {
let isIncluded: (Element) -> Bool
}
struct Map<Input, Output> {
let transform: (Input) -> Output
}
我们需要一种开始的方式,所以让我们使用恒等映射
extension Map where Input == Output {
init(on: Input.Type) { transform = { $0 }}
}
我们需要一种方法来考虑 keyPaths
extension Map {
func keyPath<ChildOutput>(_ keyPath: KeyPath<Input, ChildOutput>) -> Map<Input, ChildOutput> {
return Map<Input, ChildOutput>(transform: { $0[keyPath: keyPath] })
}
}
最后我们要创建一个实际的过滤器
extension Map {
func inRange<RE: RangeExpression>(_ range: RE) -> Filter<Input> where RE.Bound == Output {
let transform = self.transform
return Filter(isIncluded: { range.contains(transform($0)) })
}
}
为“过去 24 小时”添加助手
extension Range where Bound == Date {
static var last24Hours: Range<Date> { return Date(timeIntervalSinceNow: -24*60*60)..<Date() }
}
现在我们可以构建一个如下所示的过滤器:
let filters = [Map(on: MyModel.self).keyPath(\.dueDate).inRange(Range.last24Hours)]
filters
类型为 Filter<MyModel>
, 所以任何其他过滤 MyModel
的东西在这里是合法的。调整你的 filteredBy
:
extension Sequence {
func filteredBy(_ filters: [Filter<Element>]) -> [Element] {
return filter{ element in filters.allSatisfy{ $0.isIncluded(element) } }
}
}
好的,这就是过滤步骤。但是您的问题基本上也是“UI 配置”,为此您想要捕获比这更多的元素。
但是您的示例用法不会让您到达那里:
// Also I want to be able to save the state of all filters like this
var activeFilters: [AnyFilter] = [ // ???
MyModel.Filters.DueDateFilter(selectedOptions: [.in24hours(past: false)]),
MyModel.Filters.StatusFilter(selectedOptions: [.a, .b])
]
如何转换 AnyFilter
进入 UI 元素?您的过滤器协议(protocol)实际上允许任何 选项类型。如果选项类型为 OutputStream
,您将如何显示 UI或 DispatchQueue
?您创建的类型没有解决问题。
这是一种解决方法。创建一个 FilterComponent 结构,它定义所需的 UI 元素并提供一种构建过滤器的方法。
struct FilterComponent<Model> {
let optionTitles: [String]
let allowsMultipleSelection: Bool
var selectedOptions: IndexSet
let makeFilter: (IndexSet) -> Filter<Model>
}
然后要创建一个日期过滤器组件,我们需要一些日期选项。
enum DateOptions: String, CaseIterable {
case inPast24hours = "In the past 24 hours"
case inNext24hours = "In the next 24 hours"
var dateRange: Range<Date> {
switch self {
case .inPast24hours: return Date(timeIntervalSinceNow: -24*60*60)..<Date()
case .inNext24hours: return Date()..<Date(timeIntervalSinceNow: -24*60*60)
}
}
}
然后我们想要一种方法来创建具有正确 makeFilter
的组件:
extension FilterComponent {
static func byDate(ofField keyPath: KeyPath<Model, Date>) -> FilterComponent<Model> {
return FilterComponent(optionTitles: DateOptions.allCases.map{ $0.rawValue },
allowsMultipleSelection: false,
selectedOptions: [],
makeFilter: { indexSet in
guard let index = indexSet.first else {
return Filter<Model> { _ in true }
}
let range = DateOptions.allCases[index].dateRange
return Map(on: Model.self).keyPath(keyPath).inRange(range)
})
}
}
有了这些,我们可以创建类型为 FilterComponent<MyModel>
的组件.无需公开内部类型(如 Date
)。无需协议(protocol)。
let components = [FilterComponent.byDate(ofField: \MyModel.dueDate)]
关于swift - 为更复杂的协议(protocol)键入删除,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53598104/
我知道如何通过iPhone开发创建sqlite数据库、向其中插入数据、删除行等,但我试图以编程方式删除整个数据库本身,但没有得到任何帮助。请有人指导我如何通过代码从设备中删除/删除整个 sqlite
请帮助指导如何在 Teradata 中删除数据库。 当我运行命令DROP DATABASE database_name时,我收到错误消息: *** Failure 3552 Cannot DROP d
Azure 警报规则的删除命令似乎不起作用,尝试了下面的方法,它返回状态为无内容,并且警报未被删除 使用的命令Remove-AzAlertRule -ResourceGroup "RGName"-Na
我在 flex 搜索中为大约50000个视频建立了索引,但是当它达到52000左右时,所有数据都被删除。嗯,这对我来说真的很奇怪,我没有为ES设置任何Heap大小或最小或最大大小的内存大小,因此它们没
我正在处理的问题是表单错误“输入由字母、数字、下划线或连字符组成的有效‘slug’。” 以下是我的表单字段验证: def clean_slug(self): slug = self.c
阅读文档,我希望 $("#wrap2").remove(".error") 从 中删除所有 .error 元素#wrap2。然而看看这个 JSFiddle: http://jsfiddle.net/h
嗨,我第一次尝试发现 laravel 我从 laravel 4.2 开始,我刚刚创建了一个新项目,但我误以为我写了这样的命令行 composer create-project laravel/lara
我已经在网上搜索了很长一段时间,但我找不到如何完全删除 apache 2.4 。 使用: Windows 7 c:\apache24\ 我已经尝试了所有命令,但没有任何效果。 httpd -k shu
可能是一个简单的答案,所以提前道歉(最少的编码经验)。 我正在尝试从任何列中删除具有特定字符串(经济 7)的任何行,并且一直在尝试离开此线程: How to drop rows from pandas
有几种方法可以删除/移除 vector 中的项目。 我有一个指针 vector ,我需要在类的析构函数中删除所有指针。 什么是最有效/最快甚至最安全的方式? // 1º std::for_each(v
我安装了一个 VNC 服务器并在某处阅读了我必须安装 xinetd 的信息。稍后我决定删除 VNC 服务器,所以我也删除了 xinetd。似乎 xinetd 删除了一些与 plesk 相关的文件,如果
我制作了一个从我们的服务器下载视频的应用。问题是: 当我取消下载时,我打电话: myAsyncTask.cancel(true) 我注意到,myAsyncTask 并没有在调用取消时停止...我的 P
是否可以在使用DELETE_MODEL删除模型之前检查模型是否存在我试图避免在尝试删除尚未创建的模型时收到错误消息。基本上我正在寻找对应的: DROP TABLE IF EXISTS 但对于模型。 最
我已经有了这个代码: 但它仍然会生成一个表行条目。 我想做的是,当输入的数量为0时,表行将被删除。请耐心等待,因为我是 php 和 mySQL 编码新手。 最佳答案 您忘记执行查询。应该是 $que
在 SharePoint 中,如果您删除/修改重复日历条目的单次出现,则不会真正删除/修改任何内容 - 相反,会创建一个新条目,告诉 SP 对于特定日期,该事件不存在或具有新参数. 因此,这可以通过删
在 routes.php 中我有以下路由: Route::post('dropzone', ['as' => 'dropzone.upload', 'uses' => 'AdminPhotoContr
在我的应用程序中,我正在尝试删除产品。当我第一次删除产品时,它会成功并且 URL 更改为/remove_category/15。我正在渲染到同一页面。现在,当我尝试删除另一个产品时,网址更改为/rem
这个问题被问了很多次,但给出的答案都是 GNU sed 特定的。 sed -i '' "/${FIND}/,+2d""$FILE" 给出“预期的上下文地址”错误。 有人可以给我一个例子,说明如何使用
在使用 V3 API 时,我找不到任何方法来删除和清理 Google map 。 我已经在 AJAX 站点中运行它,所以我想完全关闭它而无需重新加载页面。 我希望有一个 .unload() 或 .de
是否可以创建一个 Azure SQL 数据库用户来执行以下操作: 针对所有表和 View 进行 SELECT 创建/更改/删除 View 但用户不应该不拥有以下权限: 针对任何表或 View 插入/更
我是一名优秀的程序员,十分优秀!