Добавить данные массива в переменную Struct - PullRequest
0 голосов
/ 28 апреля 2019

Я хочу объединить данные массива в мою структурную переменную

Ниже приведен код

Я хочу добавить значения массива расстояния в покое -> расстояние

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 ]

1 голос
/ 28 апреля 2019

Здесь много чего происходит, поэтому я проведу вас через решение.

Прежде всего, rest - плохое имя переменной.Когда я прочитал это первым, я подумал, что это «остальное», как и остаток чего-то, и искал, где находятся «основные» данные.Нажатие клавиш не стоит вам $, вы можете просто набрать restaurants.

Во-вторых, вы создаете пустой массив и вручную добавляете в него все эти рестораны.Вместо этого вы можете просто создать массив из литерала массива, который содержит все рестораны напрямую.Это исключает необходимость иметь отдельные

. Чтобы ответить на ваш прямой вопрос, вы можете использовать zip для повторения rest и distance вместе, но проблема в том, что rest1, rest2... переменные, которые были обречены на провал.Что происходит, когда вы копируете / вставляете несколько строк и забываете поменять одну из них, случайно написав rest.append(rest6); rest.append(rest6), забыв rest7?

В-третьих, ваша findDistance(from:long:) функция занимает две Double с(широта и долгота) и использует их для построения CLLocation.Но когда вы посмотрите, где используется эта функция, у вас уже есть CLLocation, который вы разбиваете на два Double s, только на findDistance(from:long:), чтобы немедленно объединить их обратно в CLLocation.Вместо этого просто заставьте findDistance принять CLLocation напрямую.

В-четвертых, тип данных Restaurants имеет имя miss.Это не множество ресторанов.Это модели одного ресторана.Назовите его соответствующим образом: 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)
}

Однако это все еще не очень хорошо.Тип данных 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).Когда я говорю someRestaurant.distance, я ожидаю расстояние до меня.Если бы это было расстояние от некоторой контрольной точки A, я бы ожидал, что API вместо этого будет написано что-то вроде someResaurant.distanceFromNorthPole, или что-то в этом роде.

Более того, почему это работа Restaurantхранить свое расстояние до чего-то еще?Что если я захочу restaurant.distanceToSouthPole, restaurant.distanceToEquator?API будет довольно раздутым, а тип restaurant в конечном итоге будет делать слишком много.А что если я restaurant.distanceToMe?Я могу двигаться, как предварительно вычисленное, сохраненное значение будет идти в ногу со мной, когда я двигаюсь?

Решение - не хранить расстояние вообще. Вместо этого предоставьте API, который пользователи этого типа данных могут использовать для вычисления расстояний до любой точки по своему выбору.


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 Double с. Это лучше для взаимодействия с API определения местоположения (где 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.

struct Restaurant {
    var name: String
    var location: CLLocation

    func distance(from other: CLLocation) -> Double {
        return self.location.distance(from: other)
    }
}

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),
]

let pointA = CLLocation(latitude: 31.461512, longitude: 74.272024) // Name me!

// and now, whenever you need the distance to pointA you can do this (for example):

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

}
0 голосов
/ 28 апреля 2019

Если я предполагаю, что ваш вопрос правильный, вы должны заполнить свойство distance каждого из ресторанов в rest с помощью переменной distance.Кроме того, предполагая, что количество переменных distance и rest равно, вы можете сделать что-то вроде этого,

if rest.count == distance.count {
   (0..<rest.count).forEach {
       rest[$0].distance = distance[$0]
   }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...