用另一个数组过滤一个 (Codable) 数组
Filter an (Codable) array by another array
我正在尝试按 ID 过滤我的 json 数据(尝试标记一些收藏夹并使用它进行过滤)
struct workoutList : Codable {
let id : Int
let title : String
let tag : String
}
func selectedWorkoutGroup(libraryFilter: Int, jsonErgWorkouts:[workoutList], workoutGroupBox: UITextField) -> [workoutList] {
var selectedGroup = [workoutList]()
let workoutFav = [1,10,100]
if libraryFilter == 0 {
// This works because I'm filtering based on 1 specific item
selectedGroup = jsonErgWorkouts.filter { [=10=].tag == workoutGroupBox.text }
} else if libraryFilter == 1 {
// Here I want to filter and show only the favorites
selectedGroup = jsonErgWorkouts.filter { [=10=].id } //
print("selectedGroup:\(selectedGroup)")
}
return selectedGroup
}
在上面的代码中,当我有 1(一个)特定项目要过滤然后我得到带有该标签的整个 json 数组时过滤器工作。
现在我想实现一个收藏夹列表,例如用户选择 ID == [1, 10 ,100] 作为他们的收藏夹。
如何使用过滤命令来完成?我尝试了一些东西并通过 SO 进行了搜索(但没有用)。大多数答案都是基于基于特定项目的过滤,例如:
selectedGroup = jsonErgWorkouts.filter { workoutFav?.contains([=11=].id) }
编辑:(省略了我是 using/storing userDefaults 中的收藏夹。这段代码给出了“表达式类型不明确,没有更多上下文”的错误
func selectedWorkoutGroup(libraryFilter: Int, jsonErgWorkouts:[workoutList], workoutGroupBox: UITextField) -> [workoutList] {
var selectedGroup = [workoutList]()
UserDefaults.standard.set([1,10,100], forKey: "workoutFavorite")
/// This one gets stored as [Any] so I cast it to [Int]
let workoutFav = UserDefaults.standard.array(forKey: "workoutFavorite") as? [Int]
if libraryFilter == 0 {
// This works because I'm filtering based on 1 specific item
selectedGroup = jsonErgWorkouts.filter { [=12=].tag == workoutGroupBox.text }
} else if libraryFilter == 1 {
selectedGroup = workoutFav.flatMap { favouriteId in // for each favourite ID
jsonErgWorkouts.filter { [=12=].id == favouriteId } // This returns Error "type of expression is ambiguous without more context"
} // flatMap joins all those arrays returns by "filter" together, no need to do anything else
print("selectedGroup:\(selectedGroup)")
}
return selectedGroup
}
最终解决方案:
从此改变
let workoutFav = UserDefaults.standard.array(forKey: "workoutFavorite") as? [Int]
对此(注意 as! 而不是 as?)
let workoutFav = UserDefaults.standard.array(forKey: "workoutFavorite") as! [Int]
使用@sweeper 的回答有效。谢谢
更新:
弄清楚为什么在转换 UserDefaults as? [Int]
的输出时会出现此错误“表达式类型不明确,没有更多上下文”并且必须使用 as! [Int]
但是如果用户没有将任何收藏夹保存到 UserDefault 中,则使用 as! [Int]
强制解包会导致应用程序崩溃。 (然后我不得不编写代码)如下所示
var workoutFav = [Int]()
if !(UserDefaults.standard.array(forKey: "workoutFavorite") == nil) {
workoutFav = UserDefaults.standard.array(forKey: "workoutFavorite") as! [Int]
}
然后根据这个 SO 简化并删除了力展开成为这个 one-line
let workoutFav = UserDefaults.standard.array(forKey: "workoutFavorite") as? [Int] ?? [Int]()
您需要为收藏夹数组中的每个 ID 执行该过滤器。结果你得到一个数组数组。要获得最终数组,您需要将这些数组连接到一个数组中。这种“将每个事物映射到一个数组并加入数组”操作就是 flatMap
所做的:
workoutFav.flatMap { favouriteId in // for each favourite ID
jsonErgWorkouts.filter { [=10=].id == favouriteId } // find workouts that match the ID
} // flatMap joins all those arrays returns by "filter" together, no need to do anything else
首先请给结构名称一个大写字母,这样你就可以区分它的实例。其次,您需要有一个新数组,您将在其中存储每个收藏夹,并永久存储该数组、核心数据或服务器上的某些基础,从那里您将获取收藏夹。
更好的方法是添加 属性 like isFavorite: Bool 默认情况下为 false,如果用户更改它,您可以将其设置为 true,这样您就可以避免为此使用 id,并且可以存储整个锻炼在一个数组中到您使用的核心数据或基础,之后您可以使用
从那里获取
let favorites = workouts.compactMap { [=10=].isFavorite == true }
这就是你的方式,但只是提一下,强烈建议你将这些类型的数据存储在用户默认值之外。
struct Fav {
let name: String
let id: String
}
let df = UserDefaults.standard
let jk = ["aaa", "bbb", "cccc"]
df.setValue(jk, forKey: "favorites")
let fav1 = Fav(name: "zzz", id: "aaa")
let fav2 = Fav(name: "bbb", id: "qqq")
let favs = [fav1, fav2]
let favIDs = df.value(forKey: "favorites") as? [String]
favIDs?.forEach({ (id) in
let f = favs.filter({[=11=].id == id}) // here it is
})
我正在尝试按 ID 过滤我的 json 数据(尝试标记一些收藏夹并使用它进行过滤)
struct workoutList : Codable {
let id : Int
let title : String
let tag : String
}
func selectedWorkoutGroup(libraryFilter: Int, jsonErgWorkouts:[workoutList], workoutGroupBox: UITextField) -> [workoutList] {
var selectedGroup = [workoutList]()
let workoutFav = [1,10,100]
if libraryFilter == 0 {
// This works because I'm filtering based on 1 specific item
selectedGroup = jsonErgWorkouts.filter { [=10=].tag == workoutGroupBox.text }
} else if libraryFilter == 1 {
// Here I want to filter and show only the favorites
selectedGroup = jsonErgWorkouts.filter { [=10=].id } //
print("selectedGroup:\(selectedGroup)")
}
return selectedGroup
}
在上面的代码中,当我有 1(一个)特定项目要过滤然后我得到带有该标签的整个 json 数组时过滤器工作。
现在我想实现一个收藏夹列表,例如用户选择 ID == [1, 10 ,100] 作为他们的收藏夹。
如何使用过滤命令来完成?我尝试了一些东西并通过 SO 进行了搜索(但没有用)。大多数答案都是基于基于特定项目的过滤,例如:
selectedGroup = jsonErgWorkouts.filter { workoutFav?.contains([=11=].id) }
编辑:(省略了我是 using/storing userDefaults 中的收藏夹。这段代码给出了“表达式类型不明确,没有更多上下文”的错误
func selectedWorkoutGroup(libraryFilter: Int, jsonErgWorkouts:[workoutList], workoutGroupBox: UITextField) -> [workoutList] {
var selectedGroup = [workoutList]()
UserDefaults.standard.set([1,10,100], forKey: "workoutFavorite")
/// This one gets stored as [Any] so I cast it to [Int]
let workoutFav = UserDefaults.standard.array(forKey: "workoutFavorite") as? [Int]
if libraryFilter == 0 {
// This works because I'm filtering based on 1 specific item
selectedGroup = jsonErgWorkouts.filter { [=12=].tag == workoutGroupBox.text }
} else if libraryFilter == 1 {
selectedGroup = workoutFav.flatMap { favouriteId in // for each favourite ID
jsonErgWorkouts.filter { [=12=].id == favouriteId } // This returns Error "type of expression is ambiguous without more context"
} // flatMap joins all those arrays returns by "filter" together, no need to do anything else
print("selectedGroup:\(selectedGroup)")
}
return selectedGroup
}
最终解决方案: 从此改变
let workoutFav = UserDefaults.standard.array(forKey: "workoutFavorite") as? [Int]
对此(注意 as! 而不是 as?)
let workoutFav = UserDefaults.standard.array(forKey: "workoutFavorite") as! [Int]
使用@sweeper 的回答有效。谢谢
更新:
弄清楚为什么在转换 UserDefaults as? [Int]
的输出时会出现此错误“表达式类型不明确,没有更多上下文”并且必须使用 as! [Int]
但是如果用户没有将任何收藏夹保存到 UserDefault 中,则使用 as! [Int]
强制解包会导致应用程序崩溃。 (然后我不得不编写代码)如下所示
var workoutFav = [Int]()
if !(UserDefaults.standard.array(forKey: "workoutFavorite") == nil) {
workoutFav = UserDefaults.standard.array(forKey: "workoutFavorite") as! [Int]
}
然后根据这个 SO 简化并删除了力展开成为这个 one-line
let workoutFav = UserDefaults.standard.array(forKey: "workoutFavorite") as? [Int] ?? [Int]()
您需要为收藏夹数组中的每个 ID 执行该过滤器。结果你得到一个数组数组。要获得最终数组,您需要将这些数组连接到一个数组中。这种“将每个事物映射到一个数组并加入数组”操作就是 flatMap
所做的:
workoutFav.flatMap { favouriteId in // for each favourite ID
jsonErgWorkouts.filter { [=10=].id == favouriteId } // find workouts that match the ID
} // flatMap joins all those arrays returns by "filter" together, no need to do anything else
首先请给结构名称一个大写字母,这样你就可以区分它的实例。其次,您需要有一个新数组,您将在其中存储每个收藏夹,并永久存储该数组、核心数据或服务器上的某些基础,从那里您将获取收藏夹。 更好的方法是添加 属性 like isFavorite: Bool 默认情况下为 false,如果用户更改它,您可以将其设置为 true,这样您就可以避免为此使用 id,并且可以存储整个锻炼在一个数组中到您使用的核心数据或基础,之后您可以使用
从那里获取 let favorites = workouts.compactMap { [=10=].isFavorite == true }
这就是你的方式,但只是提一下,强烈建议你将这些类型的数据存储在用户默认值之外。
struct Fav {
let name: String
let id: String
}
let df = UserDefaults.standard
let jk = ["aaa", "bbb", "cccc"]
df.setValue(jk, forKey: "favorites")
let fav1 = Fav(name: "zzz", id: "aaa")
let fav2 = Fav(name: "bbb", id: "qqq")
let favs = [fav1, fav2]
let favIDs = df.value(forKey: "favorites") as? [String]
favIDs?.forEach({ (id) in
let f = favs.filter({[=11=].id == id}) // here it is
})