Home > database >  SwiftUI: How to sort array indices without enumerated()
SwiftUI: How to sort array indices without enumerated()

Time:11-15

I am struggling with sorting array in SwiftUI. I am looping through my array in ForEach using indices and I want to sort the whole array. I have objects that can't be Hashable because of CGSize value that's why I can't use enumerated(). After hours of trying I still don't know how to achieve sorted array.

Here is code for object:

struct Object: Identifiable {
  var id = UUID()
  var position: CGPoint = .zero
  var num: Int
}

and ContentView:

struct ContentView: View {
  @State var objects = [
    Object(num: 3),
    Object(num: 5),
    Object(num: 6),
    Object(num: 2),
    Object(num: 4),
    Object(num: 1)
  ]
    var body: some View {
        VStack {
          ForEach(objects.sorted(by: {$0.num > $1.num}).indices, id:\.self) { i in
            Text("\(objects[i].num)")
          }
        }
        .padding()
    }
}

CodePudding user response:

Your code does not produce the expected results because you use the indices of the sorted array as subscripts to the original array: Both

objects.indices
objects.sorted(by: {$0.num > $1.num}).indices

are the range 0 ..< objects.count, sorting the array has no effect. And therefore does

Text("\(objects[i].num)")

display the objects in their original order.

A quick fix would be to sort the indices instead:

ForEach(objects.indices.sorted(by: {objects[$0].num > objects[$1].num}), id:\.self) { i in
    Text("\(objects[i].num)")
}

But if you add Hashable conformance to your custom type

extension Object : Hashable {
    func hash(into hasher: inout Hasher) {
        hasher.combine(id)
        hasher.combine(position.x)
        hasher.combine(position.y)
        hasher.combine(num)
    }
}

then displaying the sorted objects becomes as simple as

ForEach(objects.sorted(by: { $0.num > $1.num})) { obj in
    Text("\(obj.num)")
}
  • Related