在SwiftUI中按值对Json数据进行分组



我是SwiftUI的新手,如有任何帮助,我们将不胜感激。

我有一个Json文件:

[
{
"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:

struct Vehicle: Hashable, Codable, Identifiable {
var id: Int
var key1: String
var key2: String
var key3: String
}

SO说"看起来你的帖子大部分都是代码;请添加更多详细信息">

我相信他们需要审查这一要求,因为我无话可说。

如果我错了,请纠正我,但据我所知,你有一些Vehicles,可能有重复的key2,你不喜欢这样。相反,您希望key2不重复。

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)
}

现在你可以这样做了,你会有car1, car2, car3而不是car1, car2, car2, car2, car3:

VStack{    
ForEach(noRepeatOrderedAllKey2) { vehicleKey2 in
Text(vehicleKey2)
.foregroundColor(.white)
}
}

我将在UserData类中引入一个新属性,以保存车辆阵列中的唯一密钥。当设置vehicles属性时,此属性会自动更新。

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阵列,并且您可以使用一个函数来返回所选钥匙的Vehicle对象。

另一种选择是使用字典,因为这样你就可以更容易地访问关键的相应车辆对象

@Published var vehicles: [Vehicle] {
willSet {
vehicleKeys = Dictionary(grouping: newValue, by: .key2)
}
}
@Published var vehicleKeys: [String: [Vehicle]] = [:]

字典未通过进行排序

最新更新