使用函数式编程平均2D数组中的列

问题描述 投票:2回答:3

作为函数式编程的练习,我决定通过我的一个项目,用Array.prototype的高阶函数替换包含for循环的函数,如mapreduce

我的项目中的一个函数在二维数组中平均列。它需要一个参数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

得到了基里尔的优雅解决方案。如果其他人有一个很好的解决方案,我很乐意看到更多。

javascript arrays node.js loops functional-programming
3个回答
2
投票

尝试使用reduceforEach函数的这个例子:

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);

2
投票

Intro..

功能编程不仅仅是编写单行和使用高阶函数,如Arary#mapArray#reduceArray#filter。顺便说一句,Array#forEach不起作用,因为它不是pure function ..

除了高阶函数,您还可以使用curryingfunction compositionmore

Algorithm

我们要做的是:

  1. 重新排列矩阵
  2. 计算矩阵内每个数组的平均值

这可以在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

0
投票
// 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);
© www.soinside.com 2019 - 2024. All rights reserved.