假设我们在Julia中有以下3个数组:
5.0 3.5
6.0 3.6
7.0 3.0
5.0 4.5
6.0 4.7
8.0 3.0
5.0 4.0
6.0 3.2
8.0 4.0
我想通过第一列的常用值合并一个数组中的3个数组,并将第二列的值相加。结果必须是以下数组:
5.0 12
6.0 11.5
7.0 3.0
8.0 7.0
我尝试vcat
和reduce
,但我没有得到假装结果。是否有一种相对简单的方法来编写指令,避免耗时的代码?谢谢!
答案 0 :(得分:3)
可能有很多方法可以做到这一点。如果您想避免编码,可以使用DataFrames包。这不是最快的解决方案,但它很短。
假设您将数组定义为变量:
x = [5.0 3.5
6.0 3.6
7.0 3.0]
y = [5.0 4.5
6.0 4.7
8.0 3.0]
z = [5.0 4.0
6.0 3.2
8.0 4.0]
然后你可以这样做:
using DataFrames
Matrix(aggregate(DataFrame(vcat(x,y,z)), :x1, sum))
:x1
部分是因为默认情况下DataFrame
的第一列被称为:x1
,如果您没有为其指定明确的名称。在这个配方中,我们将矩阵转换为DataFrame
聚合它们并将结果转换回矩阵。
答案 1 :(得分:3)
如果没有额外的包,可能的解决方案可能是
function aggregate(m::Array{<:Number,2}...)
result=sortrows(vcat(m...))
n = size(result,1)
if n <= 1
return result
end
key_idx=1
key=result[key_idx,1]
for i in 2:n
if key==result[i,1]
result[key_idx,2:end] += result[i,2:end]
else
key = result[i,1]
key_idx += 1
result[key_idx,1] = key
result[key_idx,2:end] = result[i,2:end]
end
end
return result[1:key_idx,:]
end
演示:
x = [5.0 3.5
6.0 3.6
7.0 3.0]
y = [5.0 4.5
6.0 4.7
8.0 3.0]
z = [5.0 4.0
6.0 3.2
8.0 4.0]
aggregate(x,y,z)
打印:
4×2 Array{Float64,2}:
5.0 12.0
6.0 11.5
7.0 3.0
8.0 7.0
注意:此解决方案也适用于任意数量的列
答案 2 :(得分:1)
鉴于以下两个假设:
然后对于大多数输入组合(即输入数组的数量,数组的大小),以下算法应该通过利用假设显着优于其他答案:
function f_ag(x::Matrix{T}...)::Matrix{T} where {T<:Number}
isempty(x) && error("Empty input")
any([ size(y,2) != 2 for y in x ]) && error("Input matrices must have two columns")
length(x) == 1 && return copy(x[1]) #simple case shortcut
nxmax = [ size(y,1) for y in x ]
nxarrinds = find(nxmax .> 0)
nxrowinds = ones(Int, length(nxarrinds))
z = Tuple{T,T}[]
while !isempty(nxarrinds)
xmin = minimum(T[ x[nxarrinds[j]][nxrowinds[j], 1] for j = 1:length(nxarrinds) ])
minarrinds = Int[ j for j = 1:length(nxarrinds) if x[nxarrinds[j]][nxrowinds[j], 1] == xmin ]
rowsum = sum(T[ x[nxarrinds[k]][nxrowinds[k], 2] for k in minarrinds ])
push!(z, (xmin, rowsum))
for k in minarrinds
nxrowinds[k] += 1
end
for j = length(nxarrinds):-1:1
if nxrowinds[j] > nxmax[nxarrinds[j]]
deleteat!(nxrowinds, j)
deleteat!(nxarrinds, j)
end
end
end
return [ z[n][j] for n = 1:length(z), j = 1:2 ]
end
如果违反了假设2,也就是说,第一列不能保证是唯一的,你仍然可以利用排序顺序,但算法会再次变得更加复杂,因为你需要另外期待每个最小索引检查重复。在这一点上,我不会让自己度过这种痛苦。
另请注意,您可以调整以下行:
rowsum = sum(T[ x[nxarrinds[k]][nxrowinds[k], 2] for k in minarrinds ])
到此:
rowsum = input_func(T[ x[nxarrinds[k]][nxrowinds[k], 2:end] for k in minarrinds ])
现在您可以输入您喜欢的任何功能,并在输入矩阵中添加任意数量的其他列。
这里可能会添加一些额外的优化,例如预分配z
,只有两个输入矩阵时的专门例程等,但我不打扰它们。