Общее расширение для массива в Swift

Честно говоря, я новичок в создании и использовании расширений.

Я хотел создать категорию (расширение в swift 3.0), которую можно было бы использовать во всем приложении для выполнения повторяющихся операций с массивом.

Пример ссылки 1

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

Здесь, в приведенном выше примере, нам нужно будет создать одно расширение, если мы выберем расширение для определенного типа данных. Я хотел получить руководство, есть ли способ создать общую категорию (Расширение в Swift).

  1. extension _ArrayType where Generator.Element == Int
  2. extension Array where Element: Equatable
  3. extension Array where Element == Int
  4. extension _ArrayType where Generator.Element == Float
  5. extension SequenceType where Self.Generator.Element: FloatingPointType
  6. extension Array where Element: DoubleValue
  7. extension Sequence where Iterator.Element == String

,и т.д...

Пример ссылки 2

Примечание. Короче говоря, мы можем считать, что я хочу выполнять действия на основе массива в одном расширении, а не просто создавать отдельное расширение для каждого типов данных в соответствии с вышеуказанным требованием.


person Jignesh Fadadu    schedule 18.04.2017    source источник
comment
Чего вы пытаетесь достичь? Какие операции вы имеете в виду?   -  person averello    schedule 18.04.2017
comment
Я хотел создать класс категории (с точки зрения цели C) для массива в быстром режиме, который будет предлагать выполнять все операции с использованием этих методов категории, определенных для различных типов данных (т.е. хотел создать методы в этом расширении, которые будут применимы к массив состоит из целых, двойных, плавающих, словарей, строк и т. д.) любого из типов.   -  person Jignesh Fadadu    schedule 18.04.2017
comment
Это звучит как просто extension Array { ... }. Какая проблема у вас с этим?   -  person Rob Napier    schedule 18.04.2017
comment
Предположим, мне нужно передать любой параметр в метод расширения, и если этот параметр будет динамического типа (т.е. int, double, float, словарь, строка и т. д.), то он должен работать с любым типом объекта. Нет необходимости создавать отдельное расширение для каждого отдельного типа данных.   -  person Jignesh Fadadu    schedule 18.04.2017
comment
Вы не можете определить общий метод, который принимает что-либо. Вы можете определить методы расширения Array, которые работают с типами «общего вида». Как метод, который работает с целыми числами, и другой, который работает с числами с плавающей запятой. Проверьте, если map(:), фильтр(:) и reduce(::) может помочь вам перед созданием пользовательских расширений.   -  person averello    schedule 18.04.2017
comment
Здесь у меня есть 5 разных контроллеров, от каждого из которых мне нужно выполнять разные операции, например, если от одного контроллера мне нужно отсортировать массив, состоящий из целых чисел в порядке возрастания или убывания. Из второго контроллера мне нужно отсортировать массив, состоящий из значений словаря в порядке возрастания или убывания на основе любого конкретного ключевого параметра. Из третьего контроллера мне нужно отсортировать массив, состоящий из типа id(Any). *************** Точно так же, если я хочу динамически создать метод для вставки, удаления, замены объекта с вышеупомянутыми типами данных, то как я могу создать общий метод, который может мне помочь?   -  person Jignesh Fadadu    schedule 18.04.2017
comment
Я всегда предпочитаю создавать повторно используемые пользовательские классы или категории во время разработки, которые помогут мне, а также другим людям, когда они будут иметь дело с любой новой вещью.   -  person Jignesh Fadadu    schedule 18.04.2017
comment
Я думаю, вам следует обернуть целое число, словарь, идентификатор (любой) в перечисление «Содержимое» и сделать его сопоставимым. В противном случае создайте содержимое протокола, соответствующее Comparable, и определите там операции, которые вы хотите, чтобы ваши контроллеры имели. Тогда каждый из ваших контроллеров будет иметь свойство Content (или Array‹Content›).   -  person averello    schedule 18.04.2017
comment
Хорошо, тогда как это поможет мне при выполнении таких операций, как простая вставка, вставка в объект, удаление последнего или первого объекта, удаление всего объекта, замена объекта, сортировка массива, содержащего словарь, и на основе ключа я буду нужно отсортировать его, содержит, удалить повторяющиеся значения и т. д. операции? То же самое для массива с остальными типами данных. Можете ли вы привести какой-либо пример для этого? Как я уже сказал, я совершенно новичок в расширении. Даже новичок в Swift 3.0.   -  person Jignesh Fadadu    schedule 18.04.2017
comment
Не могли бы вы обновить свой вопрос, указав, что вы на самом деле пытаетесь сделать?   -  person LinusGeffarth    schedule 21.04.2017
comment
Я уже предоставил все подробности вопроса и комментарии, не могли бы вы просмотреть его?   -  person Jignesh Fadadu    schedule 21.04.2017
comment
@JohnPatel Совершенно непонятно, о чем вы спрашиваете. Было бы очень полезно, если бы вы могли отредактировать свой вопрос с конкретным примером проблемы, которую вы пытаетесь здесь решить. Людям не нужно копаться в комментариях, чтобы понять вопрос.   -  person Hamish    schedule 22.04.2017
comment
@JohnPatel Что вы подразумеваете под От третьего контроллера мне нужно отсортировать массив, состоящий из типа id(Any)? Вы не можете отсортировать массив из чего угодно — потому что по чему вы вообще можете его сортировать? Вы ничего не знаете об элементах. На самом деле, вы, вероятно, не хотели иметь [Any] в первую очередь.   -  person Hamish    schedule 22.04.2017
comment
Большинство функций, которые вы упомянули, уже реализованы внутри Array, если ваш Element реализует Equatable...   -  person farzadshbfn    schedule 23.04.2017
comment
@Hamish Мой друг, моя главная забота здесь - найти способ создать такое расширение, которое может быть полезно всем разработчикам, а не только мне.   -  person Jignesh Fadadu    schedule 24.04.2017
comment
Это не помогает прояснить ваш вопрос @JohnPatel. Вам нужно сосредоточиться на конкретной проблеме, которую вы пытаетесь здесь решить – в настоящее время ваш вопрос слишком неясен. Как было сказано выше, почему extension Array { ... } не решает вашу проблему? Это расширение, которое будет применимо к массиву, состоящему из целых чисел, двойных чисел, чисел с плавающей запятой, словаря, строки и т. д.) любого из типов.   -  person Hamish    schedule 24.04.2017
comment
Если вы хотите только сортировать свои массивы, то уже есть метод сортировки, достаточно гибкий, чтобы его можно было изменить с помощью любой необходимой функции сравнения. Однако вы, похоже, хотите сохранить отсортированный массив (учитывая ваш упор на такие методы, как insert, create и update, которые есть для массивов, но не будут< /i> вроде как) это будет довольно сложно. Поскольку массив является struct, вы не можете расширить его и можете добавлять к нему методы только через extension, а не поля. Вероятно, вам придется реализовать общий класс со всеми необходимыми методами Array и sort-функцией.   -  person Patru    schedule 27.04.2017
comment
@Patru, спасибо за ответ. Вот в чем мое замешательство и вопрос. Есть ли какой-то конкретный способ решить эту проблему. Потому что в текущем сценарии нам нужно будет иметь дело с каждым типом данных отдельно, а не с каким-либо общим решением. Любая помощь действительно ценна заранее.   -  person Jignesh Fadadu    schedule 27.04.2017
comment
Не совсем уверен, правильно ли я понял, но если я правильно понимаю вашу проблему, то вы делаете сохранение отсортированного массива? Если это то, что вы делаете, я бы предложил вам Google для этого. Быстрый взгляд приведет вас к этой записи в блоге, которая приведет вас к репозиторию GitHub. с готовой реализацией. На первый взгляд кажется, что он использует структуру, состоящую из массива и функции сравнения, как я уже предлагал ранее. Проверьте его, чтобы увидеть, соответствует ли он вашим потребностям.   -  person Patru    schedule 27.04.2017


Ответы (2)


Как упоминалось в комментариях, один из способов добиться этого — создать собственный протокол, который будут использовать типы, которые вы хотите охватить (в комментариях кто-то назвал его Content, использованный ниже для этого примера) (от первый источник):

protocol Content {
    var hash: String { get }
}
extension Array where Element : Content {

    func filterWithId(id : String) -> [Element] {
        return self.filter { (item) -> Bool in
            return item.id == id
        }
    }
}

Однако кажется, что исходный вопрос в основном касается общих расширений для массивов, которые, как говорится в одном комментарии, невозможны, но 100% возможны в Swift (на самом деле это большая функция Swift) (от второй источник).

Например, если вы хотите определить конкретный метод расширения только для Ints, вы можете сделать это:

extension Sequence where Iterator.Element == Int {
    var sum: Int {
        return reduce(0, +)
    }
}

Похоже, что первоначальные требования вопроса - это методы расширения, которые могут не зависеть от типа данных и, следовательно, должны быть общими. Если я правильно понимаю, кажется, что эти типы данных в целом имеют некоторое соответствие Equatable и/или Hashable, что является минимальным требованием для работы такого рода универсальных вещей. Однако с этим соответствием элемента это возможно как таковое:

extension Sequence where Iterator.Element is Equatable {
    func extensionMethodName<T: Equatable>(_ input: [T], singleElement: T) -> [T] {
        // T is now a generic array of equatable items. You can implement whatever extension logic you need with these. 
        // I added different ways of passing in and returning this generic type, but the only thing that is likely going to be consistent is the `<T: Equatable>` which is Swift standard syntax for declaring generic type parameters for a method.
    }
}

Синтаксис Swift быстро меняется, и то, что здесь есть, может быстро устареть, но это руководство постоянно обновляется Apple и показывает самый последний синтаксис для Generics, использованного выше ^.

Мой ответ основан на паре StackOverflow вопросов/ответов, использованных для примера/синтаксиса выше ^. Источник: (источник SO) (источник SO 2)

Таким образом, все вышеперечисленные методы могут быть объединены для полностью индивидуального решения расширения, которое имеет как общие функции/переменные для всех ваших Array типов, так и при этом имеет переопределения расширения для конкретного типа.

person BHendricks    schedule 22.04.2017
comment
вы привели действительно хороший пример здесь. Но это предложение немного отличается от моего вопроса, спасибо. - person Jignesh Fadadu; 28.04.2017

В предложении where вы указываете «Если тип элемента имеет эти правила, рассмотрите это расширение».

Вам не нужно реализовывать все методы во всех расширениях.

Например:

  • Вы хотите расширить Array<Element>, чтобы он обычно имел метод foo(_:Element):

    extension Array {
        func foo(bar: Element) { /*your code goes here */ }
    }
    
  • Вы хотите расширить Array<Element> там, где Element реализовал Equatable (включая Int, Double и... или любые структуры/классы, которые вы пометили как Equatable):

    extension Array where Element: Equatable {
        func find(value: Element) -> Bool { 
            return index(of: value) != nil
        }
    }
    
  • Вы хотите расширить Sequence в случаях, когда Element равно Numeric, иметь переменную sum только для чтения:

    extension Sequence where Element: Numeric {
        var sum: Element { 
            return reduce(0, +)
        }
    }
    
  • Вы хотите расширить Collection<Collection<Element: Equatable>>, чтобы иметь метод для сравнения с 2D-коллекциями:

    extension Collection
        where Iterator.Element: Collection, 
        Iterator.Element.Iterator.Element: Equatable {
    
        func compare(to: Self) -> Bool {
            let flattenSelf = self.reduce([], +)
            let flattenTo = to.reduce([], +)
    
            return flattenSelf.count == flattenTo.count &&
                zip(flattenSelf, flattenTo).reduce(true) { $0 && $1.0 == $1.1 }
        }
    }
    

Вам не нужно расширять массив или коллекцию, чтобы иметь такие методы, как sort, find и т. д. Большинство этих методов уже расширены внутри компилятора, если ваш Element: Equatable или Element: Comparable. используя map, filter и reduce, вы можете создавать более сложные структуры с небольшим количеством кода.

person farzadshbfn    schedule 22.04.2017
comment
это полезный ответ, но я прошу немного о другом. Спасибо. - person Jignesh Fadadu; 28.04.2017
comment
Да, я понял вашу проблему, но на самом деле именно так ios-engnieers предлагают быстро кодировать. например, одно расширение для каждого делегата, одно расширение для каждой функциональности кода и т. д. - person farzadshbfn; 28.04.2017
comment
Спасибо @farzadshbfn за ваше драгоценное время. - person Jignesh Fadadu; 31.05.2018