Нужна помощь в реорганизации данных в массиве структур в Swift - PullRequest
0 голосов
/ 05 августа 2020

Мне кажется, что ответ здесь должен быть очевиден, и я должен сам разобраться в этом, но после целого дня борьбы я думаю, что имеет смысл попросить о помощи. У меня есть массив структур, который я создал, сначала декодировав файл данных JSON, а затем отфильтровав часть его элементов в свою собственную модель. Мне нужно реорганизовать данные, чтобы я мог использовать их для заполнения 3 связанных средств выбора, где пользователь выберет определенные c параметры поиска.

Моя модель выглядит так:

    struct Brand: Hashable, Comparable {
    static func == (lhs: Brand, rhs: Brand) -> Bool {
        return lhs.name == rhs.name && lhs.models == rhs.models
    }
    
    static func <(lhs: Brand, rhs: Brand) -> Bool {
        return lhs.name < rhs.name
    }
    var name: String
    var models: [Model]

    init(name:String, models:[Model]) {
        self.name = name
        self.models = models
    }
}

struct Model: Hashable, Comparable {
    static func == (lhs: Model, rhs: Model) -> Bool {
        return lhs.name == rhs.name && lhs.years == rhs.years
    }
    
    static func <(lhs: Model, rhs: Model) -> Bool {
        return lhs.name < rhs.name
    }
    var name: String
    var years: [String]

    init(name:String, years:[String]) {
        self.name = name
        self.years = years
    }
}

После передачи данных из JSON и выполнения некоторой реорганизации (т.е. удаления дубликатов) у меня теперь есть массив от 50 до 100 структур. В настоящее время несколько структур повторяют один и тот же бренд, а затем имеют ОДНУ отдельную модель. Мне нужно реорганизовать его так, чтобы каждая структура имела только ОДИН бренд, но внутри нее был массив моделей. Очевидно, что структура данных настроена для этого. Вот как сейчас выглядят данные (из дампа консоли):

▿ 5 elements
▿ PickerTesting.Brand
    - name: "Cannondale"
    ▿ models: 1 element
    ▿ PickerTesting.Model
        - name: "SystemSix Carb"
        ▿ years: 1 element
        - "2020"
▿ PickerTesting.Brand
    - name: "Cannondale"
    ▿ models: 1 element
    ▿ PickerTesting.Model
        - name: "SuperX Wmn\'s"
        ▿ years: 1 element
        - "2020"
▿ PickerTesting.Brand
    - name: "Cannondale"
    ▿ models: 1 element
    ▿ PickerTesting.Model
        - name: "Synapse Carb"
        ▿ years: 1 element
        - “2020"
PickerTesting.Brand
    - name: "Pinarello"
    ▿ models: 1 element
    ▿ PickerTesting.Model
        - name: "Razha"
        ▿ years: 1 element
        - "2021"
▿ PickerTesting.Brand
    - name: "Pinarello"
    ▿ models: 1 element
    ▿ PickerTesting.Model
        - name: "Angliru"
        ▿ years: 1 element
        - "2021"

И мне НЕОБХОДИМО ПОЛУЧИТЬ ЭТО, ЧТОБЫ ВЫГЛЯДИТЬ:

▿ 2 elements
▿ PickerTesting.Brand
    - name: "Cannondale"
    ▿ models: 3 element
    ▿ PickerTesting.Model
        - name: "SystemSix Carb”, “SuperX Wmn”, “Synapse Carb"
        ▿ years: 1 element
        - “2020"
PickerTesting.Brand
    - name: "Pinarello"
    ▿ models: 2 element
    ▿ PickerTesting.Model
        - name: “Razha”, “Angliru"
        ▿ years: 1 element
        - "2021"

Я работал, чтобы попробовать до l oop через элементы с той же торговой маркой, скопируйте модели (и, следовательно, годы) в пустой массив, а затем в конце повторяющихся торговых марок добавьте модели к единой торговой марке. Этот logi c по-прежнему кажется мне правильным, и я смог объединить несколько моделей под одним брендом. Но мой код представляет собой абсолютный беспорядок: то, что у меня есть, продолжает повторяться для одних и тех же брендов и создавать повторяющиеся структуры с несколькими моделями. Что еще хуже, мое ранее успешное использование Array (Set (Data)) для удаления дубликатов не удалось. Вот моя текущая функция, которую я стесняюсь здесь показывать - но в интересах обучения. Счетчик явно неправильный, но моя попытка использовать для индекса в циклах диапазона привела либо к бесконечным циклам, либо к выводу десятков тысяч элементов. Я все еще не уверен, почему значение счетчика всего 10 даст ТАК МНОГО результатов, но результаты никогда не выходят за рамки первых двух брендов (их около 10); вместо этого они просто продолжают повторять результаты. Примечание: в приведенном ниже коде uglyData, взятый в качестве аргумента этой функции, является моим текущим массивом структур, как описано выше.

Прошу прощения, что это не более лаконично, благодарен за любые указания . Повторяю, я чувствую, что это не должно быть слишком сложно, но я нахожусь на краю. время через. Вероятно, лучшим решением будет написать одну функцию в go из JSON в нужную мне форму. Я работаю над этим сейчас, но не обязательно близок к успеху.

func getBrandsAll() -> [Brand] {
var brands: [Brand] = []
let allFrames = frameData
    for i in 0..<allFrames.count {
        brands.append(Brand(name: allFrames[i].brand, models: 
        [Model(name:  allFrames[i].model, years: [allFrames[i].year.description])]))
    }
    let unique = Array(Set(brands))
    let sorted = unique.sorted()
    return sorted
}

Ответы [ 2 ]

1 голос
/ 05 августа 2020

Я бы сделал это непосредственно при разборе функции JSON. Возможно, используя словарь с названием бренда в качестве ключа и массив моделей в качестве значения. следовательно, когда вы анализируете свой json, вы можете проверить, существует ли ключ, если он не существует, вы добавляете его в словарь с пустым массивом или массивом с первой моделью.

В конце вы можете преобразовать каждый элемент своего словаря в бренд

var brands: [String:[Model]] = []
let allFrames = frameData
var currentBrand:String
for i in 0..<allFrames.count {
    currentBrand = allFrames[i].brand
    if(brands[currentBrand] == nil)
    {
        brands[currentBrand] = [Model(name:  allFrames[i].model, years: [allFrames[i].year.description])]
    }
    else
    {
    brands[currentBrand]?.append(Brand(name: allFrames[i].brand, models: 
    [Model(name:  allFrames[i].model, years: [allFrames[i].year.description])]))
    }
}    

Затем вы можете go поверх этого словаря и создать свой объект бренда

0 голосов
/ 06 августа 2020

Отвечая на свой вопрос, после большой помощи хорошего друга с гораздо большими знаниями, чем я, 25-летним опытом программирования и большим терпением. Спасибо также La pieuvre за помощь. Результат начинается с того же самого, что и его предложение, но для хранения бренда / модели и местоположения индекса используется второй словарь. Я также изменил структуру данных, чтобы сделать годы набором, а не массивом. Таким образом, ни марка, ни модель не дублируются, и, хотя есть годы, дубликаты не добавляются в набор.

Вот код:

    func getBrandsAll() -> [Brand] {
    var brands: [String : Brand] = [:]
    var modelHelper: [String : [String : Int]] = [:]
    let allFrames = frameData
    
    for i in 0..<allFrames.count {
        let brand = allFrames[i].brand
        if brands[brand] == nil {
            brands[brand] = Brand(name: brand,
                models: [Model(name: allFrames[i].model, years: [allFrames[i].year])])

            modelHelper[brand] = [allFrames[i].model : 0]
        }
        else if modelHelper[brand]?[allFrames[i].model] == nil {
            brands[brand]?.models.append(Model(name: allFrames[i].model,
                years: [allFrames[i].year]))

            modelHelper[brand]?[allFrames[i].model] = (brands[brand]?.models.count)! - 1
        }
        else {
            let modelIdx = modelHelper[brand]?[allFrames[i].model] ?? 0
            brands[brand]?.models[modelIdx].years.insert(allFrames[i].year)
        }
    }
    var brandslist: [Brand] = []
        for (_,value) in brands {
            brandslist.append(value)
            }
    return brandslist.sorted()
}

Результаты - это данные, которые выглядят вот так:

▿ PickerTesting.Brand
- name: "Lynskey"
▿ models: 5 elements
    ▿ PickerTesting.Model
    - name: "Roadback Touring"
    ▿ years: 1 member
        - 2020
    ▿ PickerTesting.Model
    - name: "R300 Road"
    ▿ years: 2 members
        - 2019
        - 2020
    ▿ PickerTesting.Model
    - name: "R500 Disc"
    ▿ years: 1 member
        - 2020
    ▿ PickerTesting.Model
    - name: "GR Race Gravel"
    ▿ years: 1 member
        - 2020
    ▿ PickerTesting.Model
    - name: "GR300 Gravel"
    ▿ years: 1 member
        - 2020
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...