[英]Average a columns in a 2D array with functional programming
作為函數式編程的一項練習,我決定遍歷我的一個項目,並用Array.prototype
的高階函數(例如map
和reduce
替換包含for循環的函數 。
我項目中的一個函數將二維數組中的列平均。 它接受一個參數samples
,該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函數可以做到這一點嗎?
從Kirill獲得了一個優雅的解決方案。 如果其他人有很好的解決方案,我希望看到更多。
使用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);
這是矩陣轉置的更巧妙的方法:
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[0].map((col, i) => a.map(row => row[i]).reduce((acc, c) => acc + c, 0) / a.length); console.log(b);
函數式編程不僅僅是編寫單行代碼 ,還使用諸如Arary#map
, Array#reduce
和Array#filter
類的高階函數 。 順便說一句, Array#forEach
不起作用,因為它不是純函數 ..
我們要做的是:
在JavaScript中看起來可能像這樣:
const averageChange = pipe(
rearrange ([]),
map (average)
)
pipe
是將多個功能組合成一個巨大功能的功能。 現在, averageChange
需要一個參數,它將通過管道傳遞。
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 ))
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]
]
至
[
[ -0.5, -0.1, -0.8, -0.8 ],
[ 4 , -0.5, -0.2, -0.5 ],
[ 0.6, 3 , 1 , 7 ]
]
我編寫的代碼比其他解決方案要多得多,但是我將邏輯划分為自己的函數,這意味着我們現在可以對代碼的其他部分使用average
函數。 另外,我已經為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) )
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);
即使對於不同的內部數組大小,這也將起作用。類似[[1],[2,3,4]]
cubes=[[1],[1,2,3]] 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);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.