避免在追加对象时乘以值

Avoid multiplying of values while appending in object

请问如何解决我的问题。我只是简单地将一些 "portals" 附加到依赖国家。 EACH "portal" 出现不止一次,我不想追加。

我有以下 class 定义:

class cls_main{
    var countries:[cls_country]!

    init() {
        countries = [cls_country]()
    }

    // "add Country"
    func addCountry(iCountry:cls_country) {
        countries.append(iCountry)
    }

}

class cls_country{

    var countryName:String!
    var portals:[cls_portal]!

    init() {
        portals = [cls_portal]()
    }

    // "add Portal"
    func addPortal(portName:String) {

        var tmpPortal = cls_portal()
        tmpPortal.portalName = portName

        println("-->Input Portal: \(tmpPortal.portalName)")

        if portals.count == 0 {
            portals.append(tmpPortal)
        } else {
            for port in portals {
                if port.portalName == portName {            
                    println("SAME INPUT, DONT SAVE")  
                } else {
                    portals.append(tmpPortal)
                }
            }
        }

    }

    func arrayCount(){
        println("Portals   : \(portals.count)")
    }
}

class cls_portal{
    var portalName:String!
}

所以我将其命名为:

var MAIN = cls_main()
var country = cls_country()

country.countryName = "USA"
country.addPortal("Dance")
country.addPortal("Dance") // Should not be appended...
country.addPortal("Hike")
country.addPortal("Swim")
country.addPortal("Play")

MAIN.addCountry(country)
country = cls_country()

添加值后,我循环遍历这些值并打印它们。结果会是这样的:

循环:

for country in MAIN.countries {
      println("COUNTRY: \(country.countryName)")

      if country.countryName == "USA" {
        for portal in country.portals {
            println(" -> PORTAL   : \(portal.portalName)")
        }
        country.arrayCount()    
      }
} 

结果:

-->Input Portal: Dance
-->Input Portal: Dance
SAME INPUT, DONT SAVE
-->Input Portal: Hike
-->Input Portal: Swim
-->Input Portal: Play
COUNTRY: USA
 -> PORTAL   : Dance
 -> PORTAL   : Hike
 -> PORTAL   : Swim
 -> PORTAL   : Swim
 -> PORTAL   : Play
 -> PORTAL   : Play
 -> PORTAL   : Play
 -> PORTAL   : Play
Portals   : 8

那么为什么每个门户最终都会成倍增加?非常感谢。

在您的搜索循环中,您在查看每个元素后决定 tmpPortal 是否在您的 portals 中。在做出决定之前,您可能需要查看所有项目。添加一个变量found,说明已经找到了。找到项目后,您可以 break 退出循环。

if portals.count == 0 {
    portals.append(tmpPortal)
} else {
    var found = false
    for port in portals {
        if port.portalName == portName {
            println("SAME INPUT, DONT SAVE")
            found = true
            // found it, stop searching
            break
        }
    }
    if !found {
        portals.append(tmpPortal)
    }
}

你在数组上循环多次,检查它。但是对于 匹配的每个元素,您都在插入门户。所以当有3个其他不匹配的元素时,你插入一个传送门3次。

尝试将您的内部循环(从 if portals.count == 一直到 else 末尾的所有内容)替换为:

if !contains(portals, { [=10=].portalName == portName }) {
    portals.append(tmpPortal)
}

contains 是一个函数,用于检查集合(如门户数组)是否包含符合特定条件的条目。标准由闭包决定,在本例中,闭包检查元素的门户名称是否与您要检查的名称相匹配。如果您不熟悉闭包,请尝试阅读 this link – 它们在 Swift 中非常有用。

P.S。您可能需要重新考虑代码中的其他一些内容。例如,最好避免像这样使用 implicitly-unwrapped optionals(即在它们后面带有 ! 的类型)。隐式可选值在 Swift 中用于某些非常特定的目的,它看起来不像在您的代码中应用。尤其是数组——最好在初始化时将数组清空。而且,如果没有国家名称的门户毫无意义,您可以将其作为初始化程序的一部分。

所以不是这个:

class cls_country{

    var countryName:String!
    var portals:[cls_portal]!

    init() {
        portals = [cls_portal]()
    }
}

// and in use:
var tmpPortal = cls_portal()
tmpPortal.portalName = portName

你可以这样写:

class cls_country {
    var portals = [cls_country]()
    // consider let not var if a country will never 
    // need to change its name:
    let countryName: String

    init(countryName: String) {
        self.countryName = countryName
        //no need to initialize portals in init
    }
}
// then later, in use:
var tmpPortal = cls_portal(countryName: portName)

如果您使用的是 Swift 1.2,则更好的解决方案是使用 Set,因此您根本不需要 addPortal 方法。 Set 提供与数组几乎相同的功能,但它只是不存储相同的值。请注意,为了使其与设置一起工作,您的 cls_portal class 必须采用可散列且公平的协议

A set stores distinct values of the same type in a collection with no defined ordering. You can use sets as an alternative to arrays when the order of items is not important, or when you need to ensure that an item only appears once.