Home > other >  Swift struct array distinct on one column (best approach)
Swift struct array distinct on one column (best approach)

Time:06-11

In this example I am making my struct array distinct by looping through each value and appending to a tmp array. I am wondering if there is a more efficient way to do this.

struct DistinctListOnName{
    init(){
        let alist: [myList] = [myList(id: 1, name: "Jeff", status: "A"),
                             myList(id: 2, name: "Mike", status: "A"),
                             myList(id: 3, name: "Mike", status: "B"),
                             myList(id: 4, name: "Ron", status: "B")]
        
        var tmp: [myList] = []
        for i in alist{
            if (tmp.filter({ item in
                item.name == i.name
            }).count == 0) {
                tmp.append(i)
            }
        }
        print(tmp)
    }
}

struct myList {
    var id: Int
    var name: String
    var status: String
    init(id: Int, name: String, status: String){
        self.id = id
        self.name = name
        self.status = status
    }
}

the above code produces this expected output

[(id: 1, name: "Jeff", status: "A"), (id: 2, name: "Mike", status: "A"), (id: 4, name: "Ron", status: "B")]

Thanks for any help!!

CodePudding user response:

Your description makes me recall question No.26 in Leetcode.

The most effective way to this question is to traverse the array, detect the duplicated element store it in the right part of the array, and remove all after traversing. Because you remove an element in the array once time, the elements after the removal of one need to move to the front of itself one by one.

I make it a generic function as an extension of the Array (require element implemented Equatable protocol):

extension Array where Element: Equatable {
    /// Description: remove duplicates without breaking order
    mutating func removeDuplicates() {
        guard self.count > 1 else {
            return
        }
        
        let numsCount = self.count
        var slow = 1
        
        for i in 1 ..< numsCount {
            if self[i - 1] != self[i] {
                self[slow] = self[i]
                slow  = 1
            }
        }
        
        self.removeSubrange(slow ..< numsCount)
    }
}

So your struct should modify to:

struct myList: Equatable {
    var id: Int
    var name: String
    var status: String
    init(id: Int, name: String, status: String){
        self.id = id
        self.name = name
        self.status = status
    }
    
    static func == (_ lhs: myList, _ rhs: myList) -> Bool {
        return lhs.name == rhs.name
    }
}

Usage:

var alist: [myList] = [myList(id: 1, name: "Jeff", status: "A"),
                     myList(id: 2, name: "Mike", status: "A"),
                     myList(id: 3, name: "Mike", status: "B"),
                     myList(id: 4, name: "Ron", status: "B")]

alist.removeDuplicates()

print(alist)
//[(id: 1, name: "Jeff", status: "A"), (id: 2, name: "Mike", status: "A"), (id: 4, name: "Ron", status: "B")]
  • Related