我有一组数组
[0.21, 0.21, 0.21, 0.21] as a,
[0.31, 0.31, 0.31, 0.31] as b,
[0.48, 0.48, 0.48, 0.48] as c
如果您注意到a1 + b1 + c1 = 1(其中a1是数组a的第一个元素)。 我想实现一个四舍五入的答案,
[0, 0, 1, 0] for a
[0, 1, 0, 0] for b
[1, 0, 0, 1] for c
步骤1。 对a1,b1,c1做一个舍入函数->这将给我们a1 = 0,b1 = 0和c1 = 0的值(对于下一组值,即a2,结转值为0.21、0.31和0.48 ,b2和c2。
第2步。
但是,由于在步骤1之后,round(a1)+ round(b1)+ round(c1) 例如
第一次分配后,c1将四舍五入为1(得到的0.52应该从c2的0.48-0.52 = -0.04减少)。类似地,由于四舍五入后a1和b1分别为0和0,因此我们会将0.21和0.31结转到a2,b2给我们a2 = 0.21 + 0.21 = 0.42和b2 = 0.31 + 0.31 = 0.62和c2 = 0.48-0.52 = -0.04 < / p>
步骤3:
对第二个元素重复步骤1,在这种情况下将变为round(a2)= round(0.42)= 0,round(b2)= round(0.62)= 1,round(c2)= round(-0.04)= 0。 Carryforwrd从a2-> 0.42,从b2-> -0.38,从c2 = -0.04到下一个元素的差异 a3将变为0.21 + 0.42 = 0.63,b3将变为= 0.31-0.38 = -0.07,而c3将变为0.48-0.04 = 0.44 将第3个元素舍入后,a3的舍入将变为1,b3-> 0,c3-> 0 ...等等。 有什么办法可以使用功能强大的数组来做到这一点?
答案 0 :(得分:1)
对于ClickHouse而言,这不是一项非常适合的任务,但是您可以利用以下事实:不会将数组拆分为两行,而是使用自定义函数来处理该数组。
这个想法很简单。首先使用groupArrayForEach
将三个数组组装成一个数组。所以
[0.21, 0.21, 0.21, 0.21] as a,
[0.31, 0.31, 0.31, 0.31] as b,
[0.48, 0.48, 0.48, 0.48] as c
成为
[[0.21, 0.31, 0.48], [0.21, 0.31, 0.48], [0.21, 0.31, 0.48]]
然后创建一个类似Carry Forward Rounding
的arrayReduce函数。看看如何在https://github.com/yandex/ClickHouse/blob/master/dbms/src/Functions/arrayReduce.cpp#L169
实际上,您不需要聚合器,一个简单的循环就足够了。
如果ClickHouse支持有状态的lambda,那会更好。我希望这样的事情
select
arrayCum
(
arr, old_carry =>
with
arrayMap(x, y -> x + y, arr, old_carry) as arr,
arrayEnumerate(arr) as idx,
arrayReduce('max', arr) as m
arrayFirstIndex(e -> e = m, arr) as i,
arrayMap(j -> if(i = j, 1, 0), idx) as rounded,
arrayMap(x, y -> x - y, arr, rounded) as carry
--
rounded, carry
, arr, arrayMap(x -> 0, arr)
)
from
( select groupArrayForEach(a) arr from data )