1

I am new to Swift and trying to write my first function that calls a closure that the user passes in. I am having trouble calling my function (which I named fun). I also was unable to find any examples of this online. I just want to call my closure (I am unsure what to pass to it?) and then make a decision based on the boolean result? This seems very easy yet I am not sure.

The goal of the method is to remove duplicates in an array based on the users specifications. In my case I may want to pass in a certain class and an array of it and then remove all classes that have the same name property (ie a name string that matches).

extension Array{

    func removeDuplicates<T: Comparable>(fun: (elem: T, arr: [T]) -> Bool) -> [T]
    {
        var array = [T]()
        for element in self
        {
            if fun(elem: T(), arr: [T])
            {
                println("hello")
            }
        }

        return array
    }


}
applejuiceteaching
  • 1,473
  • 3
  • 13
  • 25
  • Sorry, it is part of an Array extension . So you would call this method on any array of your choosing. I updated the code block. – applejuiceteaching Jun 07 '15 at 14:11
  • 2
    I don't see yet what you are actually trying to achieve. In any case, you *cannot* write an array extension method that applies only to restricted types of elements (i.e. only to arrays of `Comparable`). See http://stackoverflow.com/questions/24938948/array-extension-to-remove-object-by-value or http://stackoverflow.com/questions/27350941/is-it-possible-to-make-an-array-extension-in-swift-that-is-restricted-to-one-cla. – Martin R Jun 07 '15 at 14:14
  • Also, this doesn't sound like it is meant to remove duplicates but instead just filter. In that case, just use the native `filter` method. – Andrew Monshizadeh Jun 07 '15 at 14:26
  • Yes, that is correct my explanation was wrong. I really just want to return an array that does not contain duplicates of the attributes I specify. – applejuiceteaching Jun 07 '15 at 14:27

1 Answers1

3

This is a slight generalization of Does there exist within Swift's API an easy way to remove duplicate elements from an array? and might be what you are looking for:

extension Array {

    func withoutDuplicates<U : Hashable>(attribute : T -> U) -> [T] {
        var result : [T] = []

        var seen : Set<U> = Set()
        for elem in self {
            let value = attribute(elem)
            if !seen.contains(value) {
                result.append(elem)
                seen.insert(value)
            }
        }

        return result
    }
}

The attribute closure is applied to each array element, and a Set is used to keep track of values that occurred already. Therefore the value type U is required to be Hashable (which is the case for strings).

Example:

struct Person : Printable {
    let firstName : String
    let lastName : String

    var description: String {
        return "\(firstName) \(lastName)"
    }
}

let array = [ 
    Person(firstName: "John", lastName: "Doe"),
    Person(firstName: "Joe", lastName: "Miller"),
    Person(firstName: "Jane", lastName: "Doe")
]

let result = array.withoutDuplicates( { $0.lastName } )
println(result)
// [John Doe, Joe Miller]

An alternative implementation is

func withoutDuplicates<U : Hashable>(attribute : T -> U) -> [T] {
    var seen : [U : Bool] = [:]
    return self.filter { seen.updateValue(true, forKey: attribute($0)) == nil }
}

which utilizes the fact that the updateValue() method of Dictionary returns the previous value for the key, and in particular returns nil if the key was not set previously. This is also just a slight generalization of @rintaro's answer to iOS Swift: Filter array to unique items.

Community
  • 1
  • 1
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382