我想将数组数据合并到我的结构变量中
下面是代码
我想在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
}
答案 0 :(得分:1)
这里有很多事情,所以我将引导您完成解决方案。
首先,rest
是一个不好的变量名。当我第一次阅读它时,我以为这是“其余的”,就像其余的东西一样,并且正在寻找“主要”数据的位置。击键不花钱,只需付restaurants
即可支付。
第二,您创建一个空数组,然后手动将所有这些餐厅添加到该数组。取而代之的是,您可以仅根据数组文字创建一个数组,该文字直接包含所有餐厅。这就不需要单独设置
要回答您的直接问题,可以使用zip
一起迭代rest
和distance
,但是问题是rest1
,rest2
,...变量注定会失败。当您复制/粘贴一堆行,而忘记更改其中的一行,不小心写了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(_:_:)
并行地迭代zip
和restaurants
,然后根据每个`距离对每个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
的工作是存储其与其他物体的距离?如果我想要Restaurant
,restaurant.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)")
}
的作用。请注意,CLLocation
和lat
的几乎所有使用都需要先将其装箱到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)
}
}
的好名字,不需要进行两阶段初始化,它可以为用户可能需要的任何点提供最新的距离数据,并且不容易出现复制粘贴错误,谢谢Restaurant
和lat
粘在一起成为long
。
CLLocation
答案 1 :(得分:0)
如果我认为您的问题正确,那么您想使用变量distance
来填充rest
中每个餐馆的distance
属性。另外,假设distance
变量和rest
变量的数量相等,则可以执行以下操作,
if rest.count == distance.count {
(0..<rest.count).forEach {
rest[$0].distance = distance[$0]
}
}