使用函数式编程平均2D数组中的列
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用函数式编程平均2D数组中的列相关的知识,希望对你有一定的参考价值。
作为函数式编程的练习,我决定通过我的一个项目,用Array.prototype
的高阶函数替换包含for循环的函数,如map
和reduce
。
我的项目中的一个函数在二维数组中平均列。它需要一个参数samples
这是一个大小为[n][LOOKBACK]
的二维数组:
[
[0.6, 4.0, -0.5],
[1.0, -0.5, -0.8],
...
]
const LOOKBACK = 3
function averageChange(samples) {
let result = []
let count = 0,
i, j
for (i = 0; i < LOOKBACK; i++) {
let accumulator = 0
for (j = 0; j < samples.length; j++) {
accumulator += samples[j][i]
}
result.push(accumulator / samples.length)
}
return result
}
console.log(
averageChange([
[0.6, 4.0, -0.5],
[1.0, -0.5, -0.8]
])
)
输出应该是一个大小为LOOKBACK
的数组,其元素是每列的平均值:
[0.8, 1.75, -0.65]
我花了一些时间试图找到解决方案,但我似乎无法想出一个。
这是否可以使用javascript的内置Array函数?
*Update
得到了基里尔的优雅解决方案。如果其他人有一个很好的解决方案,我很乐意看到更多。
尝试使用reduce
和forEach
函数的这个例子:
let a = [
[0.6, 4.0, -0.5],
[3.0, -0.5, -0.1],
[1.0, -0.2, -0.8],
[7.0, -0.5, -0.8]
];
let b = a.reduce((acc, cur) => {
cur.forEach((e, i) => acc[i] = acc[i] ? acc[i] + e : e);
return acc;
}, []).map(e => e / a.length);
console.log(b);
Intro..
功能编程不仅仅是编写单行和使用高阶函数,如Arary#map
,Array#reduce
和Array#filter
。顺便说一句,Array#forEach
不起作用,因为它不是pure function ..
除了高阶函数,您还可以使用currying,function composition和more。
Algorithm
我们要做的是:
- 重新排列矩阵
- 计算矩阵内每个数组的平均值
这可以在JavaScript中看起来像:
const averageChange = pipe(
rearrange ([]),
map (average)
)
pipe
是将多个函数组合成一个巨大函数的函数。 averageChange
现在采取一个论点,这将流过管道。
Rearrange
const rearrange = yss => xss =>
xss[0].length === 0
? yss
: rearrange
(concat (yss) ([ map ( getIndex (0) ) ( xss ) ]))
(map ( slice (1, xss[0].length) ) ( xss ))
这看起来很神秘。由于咖喱和功能组成,我们可以重写它:
const rearrange = yss => xss =>
matrixLength (xss) === 0
? yss
: rearrange
(concat (yss) ([ firstIndeces ( xss ) ]))
(excludeFirstIndeces ( xss ))
qazxsw poi是一个递归函数,可以转换矩阵
rearrange
至
[
[0.6, 4.0, -0.5],
[3.0, -0.5, -0.1],
[1.0, -0.2, -0.8],
[7.0, -0.5, -0.8]
]
Working Code Example
我编写了比其他解决方案更多的代码,但是我将逻辑划分为我自己的函数,这意味着我们现在可以使用像[
[ -0.5, -0.1, -0.8, -0.8 ],
[ 4 , -0.5, -0.2, -0.5 ],
[ 0.6, 3 , 1 , 7 ]
]
这样的函数来代码的其他部分。另外,我为average
等编写了curryied版本来编写它们。如果你使用一个库,这将是多余的..
Array#map
// helper functions
const pipe = (...fns) => fns.reduce((f, g) => (...args) => g(f(...args)))
const getIndex = i => xs =>
xs[i]
const map = f => xs =>
xs.map(f)
const reduce = f => seel => xs =>
xs.reduce(f)
const concat = ys => xs =>
xs.concat(ys)
const slice = (start, end) => xs =>
xs.slice(start, end)
const average = xs =>
reduce ((sum, x) => sum + x) (0) (xs) / xs.length
const length = xs =>
xs.length
const matrixLength = pipe(
getIndex(0),
length
)
const firstIndex = getIndex (0)
const firstIndeces = map ( firstIndex )
const excludeFirstIndex = xss => slice (1, matrixLength (xss)) (xss)
const excludeFirstIndeces = map ( excludeFirstIndex )
// business logic
const rearrange = yss => xss =>
matrixLength (xss) === 0
? yss
: rearrange
(concat (yss) ([ firstIndeces ( xss ) ]))
(excludeFirstIndeces ( xss ))
const averageChange = pipe (
rearrange ([]),
map(average)
)
const values = [
[0.6, 4.0, -0.5],
[3.0, -0.5, -0.1],
[1.0, -0.2, -0.8],
[7.0, -0.5, -0.8]
]
console.log( averageChange (values) )
即使对于不同的内部数组大小,这也会起作用。像这样[[1],[2,3,4]]
var a=[];var b=[];
var i = 0; j = 0;
cubes.forEach(function each(item,length) {
if (Array.isArray(item)) {
item.forEach(each);
j++;
i = 0;
} else {
if(a[i]===undefined){
a[i]=0;b[i]=0}
a[i]=(a[i]*b[i]+item)/(b[i]+1);
b[i]=b[i]+1;
i++;
}
});
console.log(a);
以上是关于使用函数式编程平均2D数组中的列的主要内容,如果未能解决你的问题,请参考以下文章
《JS权威指南学习总结--8.8 函数式编程和8.8.1使用函数处理数组》