>>> li=[0,1,2,3,4,5]
并在列表的任何/所有列表上执行切片分配:
>>> li[2:]=[99] # note then end index is not needed if you mean 'to the end' >>> li [0,99]
Swift有一个类似的切片赋值(这是在swift交互式shell中):
1> var arr=[0,5] arr: [Int] = 6 values { [0] = 0 [1] = 1 [2] = 2 [3] = 3 [4] = 4 [5] = 5 } 2> arr[2...arr.endindex-1]=[99] 3> arr $R0: [Int] = 3 values { [0] = 0 [1] = 1 [2] = 99 }
到现在为止还挺好.但是,有几个问题.
首先,swift不适用于空列表或索引位于endindex之后.如果切片索引在结束索引之后,则Python附加:
>>> li=[] # empty >>> li[2:]=[6,7,8] >>> li [6,8] >>> li=[0,2] >>> li[999:]=[999] >>> li [0,999]
4> var arr=[Int]() arr: [Int] = 0 values 5> arr[2...arr.endindex-1]=[99] Fatal error: Can't form Range with end < start
这很容易测试和编码.
第二个问题是杀手:它的速度非常慢.考虑这个Python代码来执行浮点列表的精确求和:
def msum(iterable): "Full precision summation using multiple floats for intermediate values" # Rounded x+y stored in hi with the round-off stored in lo. Together # hi+lo are exactly equal to x+y. The inner loop applies hi/lo summation # to each partial so that the list of partial sums remains exact. # Depends on IEEE-754 arithmetic guarantees. See proof of correctness at: # www-2.cs.cmu.edu/afs/cs/project/quake/public/papers/robust-arithmetic.ps partials = [] # sorted,non-overlapping partial sums for x in iterable: i = 0 for y in partials: if abs(x) < abs(y): x,y = y,x hi = x + y lo = y - (hi - x) if lo: partials[i] = lo i += 1 x = hi partials[i:] = [x] return sum(partials,0.0)
它的工作原理是保持hi / lo部分求和,使msum([.1] * 10)精确地产生1.0而不是0.9999999999999999. ms的等效msum是Python中math library的一部分.
我试图在swift中复制:
func msum(it:[Double])->Double { // Full precision summation using multiple floats for intermediate values var partials=[Double]() for var x in it { var i=0 for var y in partials{ if abs(x) < abs(y){ (x,y)=(y,x) } let hi=x+y let lo=y-(hi-x) if abs(lo)>0.0 { partials[i]=lo i+=1 } x=hi } // slow part trying to replicate Python's slice assignment partials[i:]=[x] if partials.endindex>i { partials[i...partials.endindex-1]=[x] } else { partials.append(x) } } return partials.reduce(0.0,combine: +) }
测试功能和速度:
import Foundation var arr=[Double]() for _ in 1...1000000 { arr+=[10,1e100,10,-1e100] } print(arr.reduce(0,combine: +)) // will be 0.0 var startTime: CFAbsoluteTime! startTime = CFAbsoluteTimeGetCurrent() print(msum(arr),arr.count*5) // should be arr.count * 5 print(CFAbsoluteTimeGetCurrent() - startTime)
在我的机器上,需要7秒才能完成. Python native msum需要2.2秒(大约快4倍),库fsum函数需要0.09秒(几乎快90倍)
我试图用arr.removeRange(i ..< arr.endindex)替换partials [i ... partials.endindex-1] = [x]然后追加.快一点但不多. 题:
>这是惯用的swift:partials [i … partials.endindex-1] = [x]
>有更快/更好的方式吗?
解决方法
Swift中非优化和优化代码之间的区别
(“-Onone”vs“-O”编译器选项,或Debug与Release配置),因此对于性能测试,请确保“Release”配置
被选中. (如果您,“发布”也是默认配置
用仪器描述代码).
使用半开范围有一些优点:
var arr = [0,5] arr[2 ..< arr.endindex] = [99] print(arr) // [0,99]
事实上,这是一个范围在内部存储的方式,它允许你
在数组末尾插入一个切片(但不超过Python中的切片):
var arr = [Int]() arr[0 ..< arr.endindex] = [99] print(arr) // [99]
所以
if partials.endindex > i { partials[i...partials.endindex-1]=[x] } else { partials.append(x) }
相当于
partials[i ..< partials.endindex] = [x] // Or: partials.replaceRange(i ..< partials.endindex,with: [x])
但是,这不是性能提升.看起来
在Swift中替换切片很慢.截断数组和
附加新元素
partials.replaceRange(i ..< partials.endindex,with: []) partials.append(x)
我的测试代码的时间从大约1.25秒减少到0.75秒电脑.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。