在SwiftUI中按值分组Json数据
我是SwiftUI的新手,任何帮助都将不胜感激 我有一个Json文件:在SwiftUI中按值分组Json数据,swift,swiftui,Swift,Swiftui,我是SwiftUI的新手,任何帮助都将不胜感激 我有一个Json文件: [ { "id": 1001, "key1": "truck", "key2": "car1", "key3": "motorcycle", }, { "id":
[
{
"id": 1001,
"key1": "truck",
"key2": "car1",
"key3": "motorcycle",
},
{
"id": 1002,
"key1": "truck",
"key2": "car2",
"key3": "motorcycle",
},
{
"id": 1003,
"key1": "truck",
"key2": "car2",
"key3": "motorcycle",
},
{
"id": 1004,
"key1": "truck",
"key2": "car2",
"key3": "motorcycle",
},
{
"id": 1005,
"key1": "truck",
"key2": "car3",
"key3": "motorcycle",
},
]
我可以达到这样的值:
VStack{
ForEach(userData.vehicles) { vehicle in
Text(vehicle.key2)
.foregroundColor(.white)
}
}
输出为:
car1
car2
car2
car2
car3
我想看到的是:
car1
car2
car3
有没有办法在SwiftUI中对键进行分组
编辑:
@MahdiBM在评论部分要求提供以下代码
车辆申报
final class UserData: ObservableObject {
@Published var showFavoritesOnly = false
@Published var vehicles = vehicleInfo
}
读取Json
let vehicleInfo: [Vehicle] = readJSON("vehicleInfo.json")
func readJSON<T: Codable>(_ named: String) -> T {
if let resPath = Bundle.main.resourcePath {
do {
let dirContents = try FileManager.default.contentsOfDirectory(atPath: resPath)
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first
let filteredFiles = dirContents.filter{ $0.contains(".json")}
for fileName in filteredFiles {
if let documentsURL = documentsURL {
let sourceURL = Bundle.main.bundleURL.appendingPathComponent(fileName)
let destURL = documentsURL.appendingPathComponent(fileName)
do {
try FileManager.default.copyItem(at: sourceURL, to: destURL)
print("Save to documents")
} catch {
print("ERROR FileManager.default.copyItem:: ", error)
}
}
}
}catch { print("ERRIR 2", error) }
}
let data: Data
do {
let fileURL = try FileManager.default
.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
.appendingPathComponent("vehicleInfo.json")
data = try Data(contentsOf: fileURL)
let foo = try JSONDecoder().decode(T.self, from: data)
// print(foo)
return foo
} catch {
fatalError("Couldn't find in main bundle.")
}
}
如是说;“看起来您的帖子大部分是代码;请添加更多详细信息。”
我相信他们需要审查这个要求,因为我没有什么可以说的了。如果我错了,请纠正我,但据我所知,您有一些
车辆可以重复使用钥匙2
,您不喜欢这样。相反,您希望key2
s不重复
var vehicles: [Vehicle] = [...]
// to group all `key2`s together, you can use `.map`:
var allKey2: [String] = vehicles.map { $0.key2 } // or `vehicles.map(\.key2)`, both are the same
// now you have all `key2`s grouped together
// to remove repetitive members, you can store the keys in a `Set` and convert them
// back to `Array`. why `Set`? because `Set` automatically removes repetitive members,
// but it also doesnt have any order for the members so we need to order the members back.
var noRepeatUnorderedAllKey2: [String] = Array(Set(allKey2))
// here we sort based on which member appeared sooner/later in the `allKey2` array
var noRepeatOrderedAllKey2: [String] = noRepeatUnorderedAllKey2.sorted {
(allKey2.firstIndex(of: $0) ?? 0) < (allKey2.firstIndex(of: $1) ?? 0)
}
如果我错了,请纠正我,但据我所知,您有一些车辆
可能有重复的钥匙2
,您不喜欢这样。相反,您希望key2
s不重复
var vehicles: [Vehicle] = [...]
// to group all `key2`s together, you can use `.map`:
var allKey2: [String] = vehicles.map { $0.key2 } // or `vehicles.map(\.key2)`, both are the same
// now you have all `key2`s grouped together
// to remove repetitive members, you can store the keys in a `Set` and convert them
// back to `Array`. why `Set`? because `Set` automatically removes repetitive members,
// but it also doesnt have any order for the members so we need to order the members back.
var noRepeatUnorderedAllKey2: [String] = Array(Set(allKey2))
// here we sort based on which member appeared sooner/later in the `allKey2` array
var noRepeatOrderedAllKey2: [String] = noRepeatUnorderedAllKey2.sorted {
(allKey2.firstIndex(of: $0) ?? 0) < (allKey2.firstIndex(of: $1) ?? 0)
}
我将在您的UserData
类中引入一个新属性,用于保存车辆阵列中的唯一钥匙。设置车辆
属性时,此属性将自动更新
final class UserData: ObservableObject {
@Published var showFavoritesOnly = false
@Published var vehicles: [Vehicle] {
willSet {
vehicleKeys = Set(newValue.map(\.key2)).sorted()
}
}
@Published var vehicleKeys: [String] = []
}
然后,您可以在ForEach
中使用vehicleKeys
数组,您可以使用一个函数返回所选钥匙的车辆对象
另一种选择是使用字典,因为这样您就可以更容易地访问钥匙对应的车辆对象
@Published var vehicles: [Vehicle] {
willSet {
vehicleKeys = Dictionary(grouping: newValue, by: \.key2)
}
}
@Published var vehicleKeys: [String: [Vehicle]] = [:]
虽然字典没有分类,但我想在您的UserData
类中引入一个新属性来保存车辆数组中的唯一钥匙。设置车辆
属性时,此属性将自动更新
final class UserData: ObservableObject {
@Published var showFavoritesOnly = false
@Published var vehicles: [Vehicle] {
willSet {
vehicleKeys = Set(newValue.map(\.key2)).sorted()
}
}
@Published var vehicleKeys: [String] = []
}
然后,您可以在ForEach
中使用vehicleKeys
数组,您可以使用一个函数返回所选钥匙的车辆对象
另一种选择是使用字典,因为这样您就可以更容易地访问钥匙对应的车辆对象
@Published var vehicles: [Vehicle] {
willSet {
vehicleKeys = Dictionary(grouping: newValue, by: \.key2)
}
}
@Published var vehicleKeys: [String: [Vehicle]] = [:]
字典没有分类,但是车辆声明是什么样子的?如何将json转换为车辆?我将此添加到我的问题中。谢谢,我需要查看车辆才能给您一个适当的答案。类似于struct Vehicle{var key1:String……}
。尽管上面的代码看起来不错,乍一看并没有任何实际问题。感谢您试图澄清我的问题。我还添加了这个。所以你只想从结构访问key2?如果不是,在JSON中,您是否认为所有元素都是相等的,其中KEY2=“CAR2”,即使ID对于每个都是不同的?车辆声明是什么样子的?如何将json转换为车辆?我将此添加到我的问题中。谢谢,我需要查看车辆才能给您一个适当的答案。类似于struct Vehicle{var key1:String……}
。尽管上面的代码看起来不错,乍一看并没有任何实际问题。感谢您试图澄清我的问题。我还添加了这个。所以你只想从结构访问key2?如果不是,在JSON中,您是否认为所有元素都是相等的,即使每个ID都不同,KEY2=“CAR2”?谢谢您的时间。我得到的类“UserData”没有初始值设定项
错误。如何初始化它?init(){vehicles=[]}
是一种方法。我这样做:ForEach(userData.vehicleKeys,id:\.self){vehicleKey in Text(vehicleKey)}
没有显示任何数据。你知道可能是什么问题吗?userData是用属性包装器@ObservedObject声明的吗?我使用@EnvironmentObject var userData:userData
。我还尝试了@ObservedObject
,但其他一些视图因此崩溃。我相信@EnvironmentObject
应该可以工作,但是没有机会,没有数据显示。谢谢您抽出时间。我得到的类“UserData”没有初始值设定项
错误。如何初始化它?init(){vehicles=[]}
是一种方法。我这样做:ForEach(userData.vehicleKeys,id:\.self){vehicleKey in Text(vehicleKey)}
没有显示任何数据。你知道可能是什么问题吗?userData是用属性包装器@ObservedObject声明的吗?我使用@EnvironmentObject var userData:userData
。我还尝试了@ObservedObject
,但其他一些视图因此崩溃。我相信@EnvironmentObject
应该可以工作,但是没有机会,没有数据显示。你是对的,非常感谢你抽出时间。我遇到以下错误:无法在属性初始值设定项中使用实例成员“vehicles”;属性初始值设定项在“self”可用之前运行
。我是这样初始化的:init(){vehicles=[]}
可能有什么问题?我需要更多的上下文,您在哪里键入的init(){vehicles=[]}
?错误是说,在使用结构的任何值之前,需要先为结构中的所有内容设置一个值,但我不明白为什么这里会这样说。我之前的评论是错误的,我在ForEach中使用了id:\.self
。您的解决方案是一流的,非常感谢您的帮助。您是对的,非常感谢您的时间。我遇到以下错误:无法在属性初始值设定项中使用实例成员“vehicles”;属性初始值设定项在“self”可用之前运行
。我是这样初始化的:init(){vehicles=[]}
可能有什么问题?我需要更多的上下文,您在哪里键入的init(){vehicles=[]}
?错误是说,在使用结构的任何值之前,需要先为结构中的所有内容设置一个值,但我不明白为什么这里会这样说。我之前的评论是错误的,我在ForEach中使用了id:\.self
。您的解决方案是一流的,非常感谢您的帮助。