我有一个简单的自定义对象数组。
我想将数组缩减为由最大尺寸选择的每种颜色的一个实例。
我提出的解决方案似乎长得笨拙,最好的方法是什么,我已经尝试过降低和过滤,但无法解决如何在这里应用。
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"))
答案 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
属性)。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 ]符合Foo
到Hashable
和Equatable
:
/* 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 } }
Set
和maxElement
的组合。
由于我使用了dfri的答案示例,因此应注意array
中的对象应符合Hashable
和Equatable
。答案只是为了展示另一种选择,我个人认为dfri的答案要好得多(而且速度更快)。
答案 2 :(得分:2)
这是一个简单而高效的解决方案,不需要Hashable
或Foo
上的任何其他修改:
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
}