按规则减少数组中对象的实例

时间:2016-02-08 08:42:44

标签: arrays swift

我有一个简单的自定义对象数组。

我想将数组缩减为由最大尺寸选择的每种颜色的一个实例。

我提出的解决方案似乎长得笨拙,最好的方法是什么,我已经尝试过降低和过滤,但无法解决如何在这里应用。

class foo {

    var color: String
    var size: Int
    var shape: String

    init(color:String, size:Int, shape:String){
        self.color = color
        self.size = size
        self.shape = shape
    }

}

var array = [foo]()

array.append(foo(color: "Blue", size: 2, shape: "Round"))
array.append(foo(color: "Red", size: 3, shape: "Square"))
array.append(foo(color: "Blue", size: 5, shape: "Round"))
array.append(foo(color: "Yellow", size: 1, shape: "Triangle"))
array.append(foo(color: "Blue", size: 1, shape: "Hexagon"))

4 个答案:

答案 0 :(得分:4)

您可以通过首先对数组进行排序,然后使用例如过滤掉重复的颜色对象来避免暴力O(n^2)嵌套循环(和枚举)解决方案。哈希值查找(下面的方法1 )或关于排序数组的巧妙排除(下面的方法2 )。

还请注意类类型命名约定(CamelCase):所以Foo而不是foo

免责声明:请不要对下面的渐近复杂性符号视而不见,因为premature optimization取决于您的程序的上下文和预期使用区域,通常是一个罪。我在下面将它们包含在内,只是为了比较不同的方法。选择你认为对你最有意义的那个。

方法1

  

最坏情况......

     
      
  • 时间复杂度O(n log n)

  •   
  • 空间复杂性O(n)

  •   
     

其中空间复杂性指的是超出阵列使用的空间   最终结果的分配。

  • Foo符合Hashable(让hashValue.color属性相关)。
  • Foo个实例的数组进行排序w.r.t.减小尺寸(.size属性)。
  • 过滤已排序的数组w.r.t.首先出现每种颜色,使用Hashable的一致性,快速使用O(1)哈希值查找Foo:Bool字典中的现有颜色。改编自Airspeed Velocity在the following answer中的评论。

方法2 (由Nikolai Ruhe提出):

  

最坏情况......

     
      
  • 时间复杂度O(n log n)

  •   
  • 空间复杂性O(1)

  •   
  • 按颜色(主要)和尺寸(次要)对数组进行排序。
  • 为具有与其前任颜色不同的颜色的元素过滤已排序的数组。

对于第三个(可能是此应用程序中最好的方法)方法see Nikolai Ruhe:s answer below,分别使用O(n) / O(n)时间/空间最差情况复杂度提供方法。

<强>实现

[此步骤仅用于方法1 ]符合FooHashableEquatable

/* Let Foo conform to Hashable */
class Foo : Hashable {

    var color: String
    var size: Int
    var shape: String

    init(color:String, size:Int, shape:String){
        self.color = color
        self.size = size
        self.shape = shape
    }

    var hashValue: Int {
        return color.hashValue
    }

}

/* And Equatable */
func ==(lhs: Foo, rhs: Foo) -> Bool {
    return lhs.color == rhs.color
}

稍后的过滤方法的设置和示例:

/* Foo array example */
var array = [Foo]()

array.append(Foo(color: "Blue", size: 2, shape: "Round"))
array.append(Foo(color: "Red", size: 3, shape: "Square"))
array.append(Foo(color: "Blue", size: 5, shape: "Round"))
array.append(Foo(color: "Yellow", size: 1, shape: "Triangle"))
array.append(Foo(color: "Blue", size: 1, shape: "Hexagon"))

按照您的规格过滤:

/* Method 1 (assumes Foo conforms to Hashable (& Equatable))   */
var addedDict = [Foo:Bool]()
var arrFiltered = array.sort{ $0.0.size > $0.1.size }
    .filter {addedDict.updateValue(true, forKey: $0) == nil }

/* Method 2 (as proposed by Nikolai Ruhe)                      */
var previousColor: String?
let arrFiltered = array.sort{ $0.color == $1.color ? $0.size > $1.size : $0.color < $1.color }
    .filter{ if $0.color != previousColor { previousColor = $0.color; return true }; return false }
    /* condensed .filter solution by @Nikolai Ruhe, thanks! */

结果:

for bar in arrFiltered {
    print(bar.color, bar.size)
}

/* Blue 5
   Red 3
   Yellow 1 */

分选步骤是该解决方案中的主要步骤(对于两种方法)。从swift/stdlib/public/core/Sort.swift.gyb开始,好像Swift使用introsort(具体来说,是一个内部结合insertion sort的混合体),在最坏的情况下运行为O(n log n)

答案 1 :(得分:3)

let result = Set(array).flatMap { color in array.filter { $0 == color }.maxElement { $0.0.size < $0.1.size } }

SetmaxElement的组合。

由于我使用了dfri的答案示例,因此应注意array中的对象应符合HashableEquatable。答案只是为了展示另一种选择,我个人认为dfri的答案要好得多(而且速度更快)。

答案 2 :(得分:2)

这是一个简单而高效的解决方案,不需要HashableFoo上的任何其他修改:

var biggestFoos = [String: Foo]()
for foo in array where biggestFoos[foo.color]?.size < foo.size {
    biggestFoos[foo.color] = foo
}
let result = Array(biggestFoos.values)

答案 3 :(得分:1)

您可以使用过滤器尝试此方法,但是当您的数组很大时,它可能非常耗时,因为您必须遍历每个元素的数组。

let arrayFiltered = array.filter { (fooElement) -> Bool in
    for (idx, fooItem) in array.enumerate() {

        if fooItem.color == fooElement.color && fooItem.size > fooElement.size {
            return false
        }
    }
    return true
}