不使用OffsetArrays.jl时,如何通过不规则循环存储与访问数组?
没问题,咱们来拆解这个问题——不用OffsetArrays.jl的核心就是把带负号的索引映射成Julia原生数组默认的正整数索引,毕竟原生数组都是从1开始的。下面一步步给你讲怎么改:
第一步:调整数组的初始化逻辑
首先,你需要根据原来的索引范围,计算出原生数组每个维度的大小:
- 对于
ka:原来的范围是0:kreps[1],总共有kreps[1]+1个元素,对应原生数组的索引1:kreps[1]+1(偏移量是+1) - 对于
kb:原来的范围是-kreps[2]:kreps[2],总共有2*kreps[2]+1个元素,对应原生数组的索引1:2*kreps[2]+1(偏移量是kreps[2]+1,这样-kreps[2]就变成1) - 对于
kc:和kb同理,偏移量是kreps[3]+1,总元素数2*kreps[3]+1
然后用这些大小初始化你的Float数组:
kreps = (8, 7, 6) ka_size = kreps[1] + 1 kb_size = 2 * kreps[2] + 1 kc_size = 2 * kreps[3] + 1 # 初始化原生数组,这里用zeros举例,你可以换成你需要的初始化方式 kvec_wts = zeros(Float64, ka_size, kb_size, kc_size)
如果之前你是用OffsetArrays填充kvec_wts的,现在填充的时候也要用同样的偏移量转换索引,比如:
# 填充数组的示例逻辑 for ka in 0:kreps[1], kb in -kreps[2]:kreps[2], kc in -kreps[3]:kreps[3] # 计算原生数组的索引 ka_idx = ka + 1 kb_idx = kb + kreps[2] + 1 kc_idx = kc + kreps[3] + 1 # 赋值,这里替换成你实际的计算逻辑 kvec_wts[ka_idx, kb_idx, kc_idx] = some_function(ka, kb, kc) end
第二步:修改循环中的数组访问
原来的循环逻辑完全不用改——你还是可以用ka、kb、kc的原始范围和条件判断,只是在访问kvec_wts的时候,把原始索引转换成原生数组的正索引就行。为了效率,你可以预先计算好偏移量,避免每次循环都重复计算:
# 预先计算偏移量,提升循环效率 ka_offset = 1 kb_offset = kreps[2] + 1 kc_offset = kreps[3] + 1 for kc=-kreps[3]:kreps[3], kb = -kreps[2]:kreps[2], ka = 0:kreps[1] if ka == 0 if kb < 0 continue end if kb == 0 && kc <= 0 continue end end # 转换索引后访问数组 ka_idx = ka + ka_offset kb_idx = kb + kb_offset kc_idx = kc + kc_offset current_wt = kvec_wts[ka_idx, kb_idx, kc_idx] # 这里执行你原来的大量计算逻辑 # ... end
为什么这样可行?
其实就是做了一个索引平移:把每个维度的起始索引从负数/0,平移到原生数组要求的1,这样所有的索引访问都符合Julia的规则,同时完全保留了你原来的循环逻辑和条件判断,不用改动业务代码。
内容的提问来源于stack exchange,提问作者Cokes
相关产品推荐
相关产品推荐

