前提・実現したいこと
Swiftでグルメアプリを製作中なのですが、エラーがなかなか解決できずかなりつまづいています。解決法やアドバイスなど頂けると幸いです。

やりたいこと
FirebaseのFirestoreから取得したデータを元に、CoreLocationを用いて現在地から近い順にデータを並べ替え、TableViewに表示したい。

今やろうとしていることは、CoreLocationを用いて現在地と店舗との距離を測定し、keyをDistanceとしてデータに追加しようとしています。しかし下記のエラーが出てしまい、うまくいきません。

まずこの方法で現在地から近い順にソートできるかも自身もないため、そのほかにもやり方などあれば教えていただきたいです。


発生している問題・エラーメッセージ

Type 'Shop' has no subscript members

該当のソースコード
shopArrayにShop型のデータが突っ込んであります。

func locationManager(_ manager: CLLocationManager, didUpdateLOcations locations: [CLLocation]){
    let localValue:CLLocationCoordinate2D = manager.location!.coordinate
    print("locations =\(localValue.latitude) \(localValue.longitude)")

    for i in 0 ..< self.shopArray.count{
        let currentLocation : CLLocation = CLLocation(latitude: localValue.latitude, longitude: localValue.longitude)
        let shopLocation : CLLocation = CLLocation(latitude: self.shopArray[i].latitude, longitude: self.shopArray[i].longitude)
        let distance = shopLocation.distance(from: currentLocation)
        shopArray[i]["distance"] = "distance" # エラーはこの行に出ます。

データの形式は下記です。

struct Shop {
    var title: String
    var recomendation: String
    var tel: String
    var station: String
    var latitude: Double
    var longitude: Double
    var price: Int
    var img: String

    var dictionary: [String: Any] {
        return [
            "title": title,
            "recomendation": recomendation,
            "tel": tel,
            "station": station,
            "latitude": latitude,
            "longitude": longitude,
            "price": price,
            "img": img
        ]
    }
}

ーーーーーーーーーーーーーーーーーーーーーーーーーー
追記 shopArrayにデータを格納するコード

func loadData() {
    let db = Firestore.firestore()
    let shopsRef = db.collection("shops")

    shopsRef.getDocuments() { (snapshot, err) in
        if let err = err {
            print("Error getting documents: \(err)")
        } else {
            if let snapshot = snapshot{
                for document in snapshot.documents {

                    print(document.data())
                    let data = document.data()
                    let title = data["title"] as? String ?? ""
                    let recomendation = data["recomendation"] as? String ?? ""
                    let tel = data["tel"] as? String ?? ""
                    let station = data["station"] as? String ?? ""
                    let latitude = data["latitude"] as? Double ?? Double()
                    let longitude = data["longitude"] as? Double ?? Double()
                    let price = data["price"] as? Int ?? Int()
                    let img = data["img"] as? String ?? ""
                    let distance = data["distance"] as? CLLocationDistance ?? Double()

                    let newShop = Shop(title: title, recomendation: recomendation, tel: tel, station: station, latitude: latitude, longitude: longitude, price: price, img: img, distance: distance)
                    self.shopArray.append(newShop)

                    func locationManager(_ manager: CLLocationManager, didUpdateLOcations locations: [CLLocation]){
                        guard let currentLocation = manager.location else {
                            print("location is nil")
                            return
                        }
                        print("locations =\(currentLocation.coordinate)")

                        for i in self.shopArray.indices{
                            //                let currentLocation : CLLocation = CLLocation(latitude: localValue.latitude, longitude: localValue.longitude)
                            let shopLocation : CLLocation = CLLocation(latitude: self.shopArray[i].latitude, longitude: self.shopArray[i].longitude)
                            let distance = shopLocation.distance(from: currentLocation)
                            self.shopArray[i].distance = distance //<-

                        }
                        self.shopArray.sort{$0.distance ?? 0.0 < $1.distance ?? 0.0}
                        self.cafeTableView.reloadData()
                    }
                }
            }
        }
    }
}

一部抜粋することによりわかりにくくなってしまっていたのでコード全文も掲載いたします。
ご迷惑をおかけして申し訳ありません。(いくつかのご指摘をいただき修正が加えてあるため、上のコードとは相違があります。)

  

protocol DocumentSerializeable {
init?(dictionary:[String:Any])
}

struct Shop {
var title: String
var recomendation: String
var tel: String
var station: String
var latitude: Double
var longitude: Double
var price: Int
var img: String
var distance: CLLocationDistance?

}



class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource,UISearchBarDelegate,CLLocationManagerDelegate{

@IBOutlet var cafeTableView: UITableView!

var shopArray = [Shop]()
var db: Firestore!

private var mySearchBar: UISearchBar!
private weak var refreshControl: UIRefreshControl!

var locationManager: CLLocationManager!
var currentLocation: CLLocation!

//検索結果が入る配列
private var searchResult = [String]()
private var myItems = [String]()

override func viewDidLoad() {
    super.viewDidLoad()
    locationManager = CLLocationManager()
    locationManager.requestWhenInUseAuthorization()
    loadData()
    let myNavBar = UINavigationBar()
    //大きさの指定
    myNavBar.frame = CGRect(x: 0, y: UIApplication.shared.statusBarFrame.height, width: self.view.frame.size.width, height: 44)
    mySearchBar = UISearchBar()
    //デリゲートを設定
    mySearchBar.delegate = self
    //大きさの指定
    mySearchBar.frame = CGRect(x: 0, y: UIApplication.shared.statusBarFrame.height, width: self.view.frame.size.width, height: 44)
    //キャンセルボタンの追加
    mySearchBar.showsCancelButton = true
    mySearchBar.placeholder = "カフェ名を入力してください"

    cafeTableView.tableHeaderView = mySearchBar
    cafeTableView.contentOffset = CGPoint(x: 0,y :44)

    self.cafeTableView.delegate = self
    self.cafeTableView.dataSource = self
         getTitle()
    initializePullToRefresh()
        }
override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    refresh()
}

func loadData() {
    let db = Firestore.firestore()
    let shopsRef = db.collection("shops")

    shopsRef.getDocuments() { (snapshot, err) in
        if let err = err {
            print("Error getting documents: \(err)")
        } else {
            if let snapshot = snapshot{
            for document in snapshot.documents {

                print(document.data())
                let data = document.data()
                let title = data["title"] as? String ?? ""
                let recomendation = data["recomendation"] as? String ?? ""
                let tel = data["tel"] as? String ?? ""
                let station = data["station"] as? String ?? ""
                let latitude = data["latitude"] as? Double ?? Double()
                let longitude = data["longitude"] as? Double ?? Double()
                let price = data["price"] as? Int ?? Int()
                let img = data["img"] as? String ?? ""
                let distance = data["distance"] as? CLLocationDistance ?? Double()

                let newShop = Shop(title: title, recomendation: recomendation, tel: tel, station: station, latitude: latitude, longitude: longitude, price: price, img: img, distance: distance)
                self.shopArray.append(newShop)
                self.cafeTableView.reloadData()



                }


            }

            }



 }
}

func locationManager(_ manager: CLLocationManager, didUpdateLOcations locations: [CLLocation]) {
    guard let currentLocation = manager.location else {
        print("location is nil")
        return
    }
    print("locations =\(currentLocation.coordinate)")

    for i in shopArray.indices {
        let shopLocation : CLLocation = CLLocation(latitude: shopArray[i].latitude, longitude: shopArray[i].longitude)
        let distance = shopLocation.distance(from: currentLocation)
        shopArray[i].distance = distance
    }

    //`locationManager(_:didUpdateLOcations:)`のように非同期に呼び出されるメソッドの中で
    //UIスレッドで実行する必要のある処理は`DispatchQueue.main.async {...}`の中に書く
    DispatchQueue.main.async {
        //`distance`プロパティの値(nilなら0.0に置き換え)でソートする
        //(SwiftのArrayはスレッドセーフではないので、ソートもUIスレッドの中で行う)
        self.shopArray.sort {$0.distance ?? 0.0 < $1.distance ?? 0.0}
        //`UITableView`の`realod()`と言ったUI操作はUIスレッドで実行するのが必須
        self.cafeTableView.reloadData()
    }
}


func getTitle(){
    let db = Firestore.firestore()

    db.collection("shops").whereField("title", isEqualTo: true)
        .getDocuments() { (snapshot, err) in
            if let err = err {
                print("Error getting documents: \(err)")
            } else {
                if let snapshot = snapshot{
                for document in snapshot.documents {
                    print("\(document.documentID) => \(document.data())")
                    let data = document.data()
                    let title = data["title"] as? String ?? ""

                    self.myItems.append(title)
                    }

                }
            }
    }

}



override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}


@IBAction func searchTapped(_ sender: Any) {
    if cafeTableView.contentOffset == CGPoint(x: 0,y :0)  {
        cafeTableView.contentOffset = CGPoint(x: 0,y :44)
        self.view.endEditing(true)

    }else{

        cafeTableView.contentOffset = CGPoint(x: 0,y :0)
        self.view.endEditing(true)

    }
}
//MARK: - 渡された文字列を含む要素を検索し、テーブルビューを再表示する
func searchItems(searchText: String){

    //要素を検索する
    if searchText != "" {
        searchResult = myItems.filter { myItem in
            return (myItem).contains(searchText)
            }

    }else{
        //渡された文字列が空の場合は全てを表示
        searchResult = myItems
    }
            cafeTableView.reloadData()
}

// MARK: - SearchBarのデリゲードメソッドたち
//MARK: テキストが変更される毎に呼ばれる
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    //検索する
    searchItems(searchText: searchText)
}

//MARK: キャンセルボタンが押されると呼ばれる
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {

    mySearchBar.text = ""
    self.view.endEditing(true)
    searchResult = myItems

    //tableViewを再読み込みする
    cafeTableView.reloadData()
}

//MARK: Searchボタンが押されると呼ばれる
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {

    self.view.endEditing(true)
    //検索する
    searchItems(searchText: mySearchBar.text! as String)
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return self.shopArray.count
}


func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "ShopListTableViewCell", for: indexPath)
    let shop = shopArray[indexPath.row]

    let img = UIImage(named:  "\(shop.img).jpg")
    cafeTableView.separatorColor = UIColor.white


    // Tag番号 1 で UIImageView インスタンスの生成
    let imageView = cell.viewWithTag(1) as! UIImageView
    imageView.image = img


    // Tag番号 2 で UILabel インスタンスの生成
    let shopName = cell.viewWithTag(2) as! UILabel
    shopName.text = "\(shop.title)"

    let placeName = cell.viewWithTag(3) as! UILabel
    placeName.text = "\(shop.station)"

    let distanceLabel = cell.viewWithTag(4) as! UILabel
    distanceLabel.text = "\(String(describing: shop.distance))"



    self.view.bringSubview(toFront: imageView)

    return cell

}
func numberOfSections(in tableView: UITableView) -> Int {
    return 1
}
func tableView(_ table: UITableView,
               heightForRowAt indexPath: IndexPath) -> CGFloat {
    return 135.0
}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

   let storyBoard = UIStoryboard(name: "Main", bundle: nil)
   let DvC = storyBoard.instantiateViewController(withIdentifier: "DetailViewController") as! DetailViewController
   let shop = shopArray[indexPath.row]


   DvC.getName = "\(shop.title)"
   DvC.getImage = UIImage(named:  "\(shop.img).jpg")!
   DvC.getNumber = "\(shop.tel)"
   DvC.getRecomend = "\(shop.recomendation)"
   DvC.getPrice = "\(shop.price)"

   self.navigationController?.pushViewController(DvC, animated: true)

}


@IBAction func getInfo(_ sender: Any) {

    print("\(shopArray)")
    print("\(currentLocation)")

}


// MARK: - Pull to Refresh
private func initializePullToRefresh() {
    let control = UIRefreshControl()
    control.addTarget(self, action: #selector(onPullToRefresh(_:)), for: .valueChanged)
    cafeTableView.addSubview(control)
    refreshControl = control
}

@objc private func onPullToRefresh(_ sender: AnyObject) {
    refresh()
}

private func stopPullToRefresh() {
    if refreshControl.isRefreshing {
        refreshControl.endRefreshing()
    }
}

// MARK: - Data Flow
private func refresh() {
    DispatchQueue.global().async {
        Thread.sleep(forTimeInterval: 1.0)
        DispatchQueue.main.async {
            self.completeRefresh()
        }
    }
}

private func completeRefresh() {
    stopPullToRefresh()
    cafeTableView.reloadData()
}