【问题标题】:Sum of Array containing custom class (Swift)包含自定义类的数组总和(Swift)
【发布时间】:2019-07-09 20:44:49
【问题描述】:

我正在寻找一种方法来获取包含在数组中的类的值的总和。我的设置如下:

class CustomClass {
    var value: Int?
    init(value: Int) {
       self.value = value
    }
}

let object1 = CustomClass(value: 2)
let object2 = CustomClass(value: 4)
let object3 = CustomClass(value: 8)

let array: [CustomClass] = [object1, object2, object3]

我目前的解决方案如下:

var sumArray = [Int]()
for object in array {
    sumArray.append(object.value!)
}
let sum = sumArray.reduce(0, +)

问题在于,对于具有许多其他值的类,它变得非常复杂,有人知道更好的解决方案吗?

【问题讨论】:

  • 当您说“非常复杂的类具有许多其他值”时,这是否意味着您也在尝试将不同类型的类的值包含到求和运算中?
  • 是的,确实如此。事实上,我的课程包含 Int 和 Date 类型,但日期类型不应该被“合并”..
  • @AndreasSchultz 到目前为止,我没有看到任何复杂的东西。您必须以某种方式将对象转换为数字(您已经在这样做了,尽管 .map 会是更好的解决方案),然后将数字相加。

标签: arrays swift sum reduce


【解决方案1】:

您可以将您的自定义类数组压缩映射为整数数组,然后将该数组缩减为其总和。喜欢,

let sum = array.lazy.compactMap { $0.value }
            .reduce(0, +)

【讨论】:

  • 使用尾随闭包,可以简化为.reduce(0, +)
  • 我会在那里放一个lazy,以跳过compactMap导致的中间数组分配
  • @Alexander 我想知道该怎么做。是不是像lazy var sum = array.compactMap { $0.value }.reduce(0, +) ??
  • 不不,lazy 属性使表达式在第一次请求时计算。它仍然涉及中间数组。相反,您使用数组的 lazy 计算属性,它返回一个惰性视图,该视图跟踪您要执行的操作,在需要结果之前不实际执行它们。 array.lazy.compactMap { $0.value }.reduce(0, +)
【解决方案2】:

您可以在array 上使用单个reduce

let sumOfValues = array.reduce({$0 += ($1.value ?? 0)})

【讨论】:

  • 没有必要为此使用reduce into。 reduce(0) { $0 + ($1.value ?? 0) }
  • @LeoDabus 你是对的,没有需要使用reduce(into:,_:),但我也没有看到使用reduce(_:,_:) 的任何优势
  • 有但我不适合向您解释。在 Swift 4 中实现 reduce(into:) 之前,人们有时需要将结果声明为变量,以便能够在闭包内对其进行更改。如果您不需要更改它,只需使用简单的 reduce 并返回总和 result 加上元素。
  • Resuming 如果你使用普通的 reduce 方法,闭包内没有变量,只有常量
【解决方案3】:

我将为您的类或结构创建一个包含值的协议。并将其声明更改为非可选。

protocol Valueable {
    var value: Int { get }
}

那么你需要让你的类符合那个协议:

class CustomClass: Valueable {
    let value: Int
    init(value: Int) {
        self.value = value
    }
}

现在您可以使用只读实例属性扩展收集协议,以返回数组中所有元素的总和。

extension Collection where Element: Valueable {
    var sum: Int {
        return reduce(0) { $0 + $1.value }
    }
} 

let object1 = CustomClass(value: 2)
let object2 = CustomClass(value: 4)
let object3 = CustomClass(value: 8)

let objects = [object1, object2, object3]

let sum = objects.sum   // 14

编辑/更新:

另一种选择是扩展序列并添加一个generic sum method,它接受其属性符合AdditiveArithmetic的关键路径


或将关联类型添加到符合 AdditiveArithmetic 的协议中:

protocol Valueable {
    associatedtype Value: AdditiveArithmetic
    var value: Value { get }
}

extension Collection where Element: Valueable {
    var sum: Element.Value { reduce(.zero) { $0 + $1.value } }
}

class CustomClass: Valueable {
    let value: Decimal
    init(value: Decimal) {
        self.value = value
    }
}

用法:

let object1 = CustomClass(value: 123.4567)
let object2 = CustomClass(value: 12.34567)
let object3 = CustomClass(value: 1.234567)

let objects = [object1, object2, object3]

let sum = objects.sum   // 137.036937

【讨论】:

  • 这太复杂了,抱歉。
  • @user3069232 这取决于你的编程水平。这是非常基本的协议用法,这是 Swift 成功的主要原因(面向协议的语言)
  • @user3069232 另一种选择是扩展序列并添加一个generic sum method,它接受其属性符合AdditiveArithmetic的关键路径
  • @user3069232 检查我上次的编辑。那是它开始变得复杂的时候。
猜你喜欢
  • 2017-05-30
  • 1970-01-01
  • 2020-11-12
  • 1970-01-01
  • 2021-04-06
  • 2016-07-09
  • 1970-01-01
  • 2013-08-10
  • 1970-01-01
相关资源
最近更新 更多