将数组数据追加到Struct变量中

时间:2019-04-28 18:32:20

标签: swift

我想将数组数据合并到我的结构变量中

下面是代码

我想在rest-> distance

中添加距离数组的值
distance = ["12.44","45.32","56.1","54.22"]

将此距离数组合并为结构变量距离

var rest : [Restaurants] = []
var distance : [String] = []

struct Restaurants {
    var name:String
    var lat:Double
    var long:Double
    var distance:String?
}

let rest1 = Restaurants(name: "English Tea House", lat: 31.461812, long: 74.272524, distance: nil)
let rest2 = Restaurants(name: "Cafe Barbera", lat: 31.474536, long: 74.268103, distance: nil)
let rest3 = Restaurants(name: "Butler's Chocolate", lat: 31.467505, long: 74.251908, distance: nil)
let rest4 = Restaurants(name: "Freddy's Cafe", lat: 31.461312, long: 74.272124, distance: nil)
let rest5 = Restaurants(name: "Arcadian Cafe", lat: 31.464536, long: 74.268603, distance: nil)
let rest6 = Restaurants(name: "Big Moes", lat: 31.467305, long: 74.256908, distance: nil)

rest.append(rest1)
rest.append(rest2)
rest.append(rest3)
rest.append(rest4)
rest.append(rest5)
rest.append(rest6)

for location in rest {
    distance.append(findDistance(from: location.lat, long: location.long))
}

// I want to add distance array values in rest -> distance 
func findDistance(from lat: Double, long: Double) -> Double {
    let source = CLLocation(latitude: 31.461512, longitude: 74.272024)
    let destination = CLLocation(latitude: lat, longitude: long)
    let distanceInMeters = source.distance(from: destination)
    return distanceInMeters
}

2 个答案:

答案 0 :(得分:1)

这里有很多事情,所以我将引导您完成解决方案。

首先,rest是一个不好的变量名。当我第一次阅读它时,我以为这是“其余的”,就像其余的东西一样,并且正在寻找“主要”数据的位置。击键不花钱,只需付restaurants即可支付。

第二,您创建一个空数组,然后手动将所有这些餐厅添加到该数组。取而代之的是,您可以仅根据数组文字创建一个数组,该文字直接包含所有餐厅。这就不需要单独设置

要回答您的直接问题,可以使用zip一起迭代restdistance,但是问题是rest1rest2 ,...变量注定会失败。当您复制/粘贴一堆行,而忘记更改其中的一行,不小心写了rest.append(rest6); rest.append(rest6),忘记了rest7时,会发生什么?

第三,您的findDistance(from:long:)函数采用两个Double(纬度和经度),并使用它们来构造CLLocation。但是,当您查看在何处使用此函数时,您已经有一个CLLocation,您可以将其分解为两个Double,仅让findDistance(from:long:)立即将它们重新组合成一个{{1 }}。相反,只需使CLLocation直接采用findDistance

第四,CLLocation数据类型被遗漏命名。这里不是多家餐馆。它为单个餐厅建模。相应地命名为:Restaurants

应用这些改进(并修复一系列缩进),我们得到:

Restaurant

直接问题

在这里,我将说明解决直接问题的过程。但是, 不要使用其中任何一个。 所有这些都是低劣的设计,旨在解决设计中的潜在缺陷。我展示它们是为了演示连续改进的外观。

现在,要解决直接的问题:

首次尝试:使用struct Restaurant { var name: String var lat: Double var long: Double var distance: String? } let restaurants = [ Restaurant(name: "English Tea House", lat: 31.461812, long: 74.272524, distance: nil), Restaurant(name: "Cafe Barbera", lat: 31.474536, long: 74.268103, distance: nil), Restaurant(name: "Butler's Chocolate", lat: 31.467505, long: 74.251908, distance: nil, Restaurant(name: "Freddy's Cafe", lat: 31.461312, long: 74.272124, distance: nil), Restaurant(name: "Arcadian Cafe", lat: 31.464536, long: 74.268603, distance: nil), Restaurant(name: "Big Moes", lat: 31.467305, long: 74.256908, distance: nil), ] var distances = [Double]() for location in restaurants { distance.append(findDistance(to: location)) } func findDistance(to destination: CLLocation) -> Double { let source = CLLocation(latitude: 31.461512, longitude: 74.272024) let distanceInMeters = source.distance(from: destination) return distanceInMeters }

第一种解决方法可能是使用zip(_:_:)并行地迭代ziprestaurants,然后根据每个`距离对每个distances进行突变。像这样:

restaurant

但是,这不起作用。由于for (restaurant, distance) in zip(restaurants, distances) { restaurant.distance = distance } 是值类型,因此循环中的Restaurant变量是数组中变量的副本。设置其距离会使副本变化,但不会影响数组中的原始副本。

第二次尝试:手动索引

我们可以通过循环遍历索引来解决此问题,尽管以一种不太漂亮的方式进行:

restaurant

第三次尝试:跳过for i in restaurants.indices { restaurants[i] = distances[i] } 数组。

第二次尝试有效,但是如果distances的唯一目的是让我们用一堆值填充它,而只是立即使用它们并丢弃它们,为什么我们都拥有数组?

distances

但是,这仍然不是很好。 for i in restaurants.indices { restaurant.location = findDistance(to: location) } 数据类型有两个阶段的初始化,即code smell。首先,我们使用Restaurant位置对其进行初始化,然后将其设置为实际位置。何必?为什么我们不直接设置位置?

nil

但这仍然是 不好的设计...

使用let distance = findDistance(to: location) let restaurants = [ Restaurant(name: "English Tea House", lat: 31.461812, long: 74.272524, distance: distance), Restaurant(name: "Cafe Barbera", lat: 31.474536, long: 74.268103, distance: distance), Restaurant(name: "Butler's Chocolate", lat: 31.467505, long: 74.251908, distance: distance), Restaurant(name: "Freddy's Cafe", lat: 31.461312, long: 74.272124, distance: distance), Restaurant(name: "Arcadian Cafe", lat: 31.464536, long: 74.268603, distance: distance), Restaurant(name: "Big Moes", lat: 31.467305, long: 74.256908, distance: nil), ] findDistance(to:)修复缺陷

Restaurant.distance到底能做什么?在内部,它与一些硬编码的未命名位置findDistance(to:)之间有一段距离。当我说CLLocation(latitude: 31.461512, longitude: 74.272024)时,我期望与我保持距离。如果它与某个参考点A之间有一段距离,那么我希望API的拼写类似于someRestaurant.distance或类似的含义。

此外,为什么someResaurant.distanceFromNorthPole的工作是存储其与其他物体的距离?如果我想要Restaurantrestaurant.distanceToSouthPole怎么办?该API会变得非常肿,并且restaurant.distanceToEquator类型最终会做得太多。如果我restaurant怎么办?我可以移动,随着移动,预先计算的存储值将如何跟上我的步伐?

解决方案是根本不存储距离。而是提供一种API,该数据类型的用户可以使用该API计算到他们选择的任意点的距离。

restaurant.distanceToMe

而且令人惊讶的是,这仍然不是我们能做到的最好的!

不要存储经纬度的双份

这就是 struct Restaurant { var name: String var lat: Double var long: Double func distance(from other: CLLocation) -> Double { let selfLocation = CLLocation(latitude: self.lat, longitude: self.long) return selfLocation.distance(from: other) } } let restaurants = [ Restaurant(name: "English Tea House", lat: 31.461812, long: 74.272524), Restaurant(name: "Cafe Barbera", lat: 31.474536, long: 74.268103), Restaurant(name: "Butler's Chocolate", lat: 31.467505, long: 74.251908), Restaurant(name: "Freddy's Cafe", lat: 31.461312, long: 74.272124), Restaurant(name: "Arcadian Cafe", lat: 31.464536, long: 74.268603), Restaurant(name: "Big Moes", lat: 31.467305, long: 74.256908), ] let pointA = CLLocation(latitude: 31.461512, longitude: 74.272024) // Name me! // and now, whenever you need the distance to pointA: for restaurant in restaurants { let distanceFromA = restaurant.distance(from: pointA) // This is for the purpose of a simple example only. Never hard code units like this, // Use `Measurement` and `MeasurementFormatter` to create textual representations // of measurements in the correct units, language and format for the user's locale. print("\(restaurant.name) is \(distanceFromA) meters from \(pointA)") } 的作用。请注意,CLLocationlat的几乎所有使用都需要先将其装箱到long中。因此,让我们直接存储它,而不是分离单个组件并独立传递它们。这样可以防止CLLocation之类的错误。

useLocation(lat: self.lat, long: self.long /* oops! */)

但是,如果执行此操作,则初始化程序现在需要一个struct Restaurant { var name: String var location: CLLocation func distance(from other: CLLocation) -> Double { return self.location.distance(from: other) } } 而不是两个单独的CLLocation / lat long。与位置API进行交互比较好(其中Double是交换位置信息的“通用货币”类型),但是对于像您的餐馆这样的硬编码位置,它会比较麻烦,因为所有初始化程序调用都变得with肿一连串对CLLocation的呼叫:

CLLocation.init(latitude:longitude:)

要解决此问题,为了方便起见,我们可以将let restaurants = [ Restaurant(name: "English Tea House", CLLocation(latitude: 31.461812, longitude: 74.272524)), Restaurant(name: "Cafe Barbera", CLLocation(latitude: 31.474536, longitude: 74.268103)), Restaurant(name: "Butler's Chocolate", CLLocation(latitude: 31.467505), longitude: 74.251908)), Restaurant(name: "Freddy's Cafe", CLLocation(latitude: 31.461312, longitude: 74.272124)), Restaurant(name: "Arcadian Cafe", CLLocation(latitude: 31.464536, longitude: 74.268603)), Restaurant(name: "Big Moes", CLLocation(latitude: 31.467305, longitude: 74.256908)), ] 塞进一个小的初始化程序中。我这样做是在CLLocation.init(latitude:longitude:)的扩展名中进行的,而不是直接在Restaurant的初始声明中进行的,因为这样做会保留编译器生成的初始化程序(称为“成员明智的初始化程序”),否则将替换为:

Restaurant

这允许我们重新获得以前的漂亮语法:

extension Restaurant {
    init(name: String, lat: Double, long: Double) {
        self.init(name: name, location: CLLocation(latitude: lat, long))
    }
}

可变性

在应用实例的生命周期内,餐厅名称和位置不太可能发生变化,因此无需使其保持可变。因此,请解决此问题:

let restaurants = [
    Restaurant(name: "English Tea House", lat: 31.461812, long: 74.272524),
    Restaurant(name: "Cafe Barbera", lat: 31.474536, long: 74.268103),
    Restaurant(name: "Butler's Chocolate", lat: 31.467505, long: 74.251908),
    Restaurant(name: "Freddy's Cafe", lat: 31.461312, long: 74.272124),
    Restaurant(name: "Arcadian Cafe", lat: 31.464536, long: 74.268603),
    Restaurant(name: "Big Moes", lat: 31.467305, long: 74.256908),
]

最后...

我们已经到了最后阶段。一个struct Restaurant { var name: String var location: CLLocation func distance(from other: CLLocation) -> Double { return self.location.distance(from: other) } } 的好名字,不需要进行两阶段初始化,它可以为用户可能需要的任何点提供最新的距离数据,并且不容易出现复制粘贴错误,谢谢Restaurantlat粘在一起成为long

CLLocation

答案 1 :(得分:0)

如果我认为您的问题正确,那么您想使用变量distance来填充rest中每个餐馆的distance属性。另外,假设distance变量和rest变量的数量相等,则可以执行以下操作,

if rest.count == distance.count {
   (0..<rest.count).forEach {
       rest[$0].distance = distance[$0]
   }
}